InquirerPiston protests World Bank-led transport conference in BaguioCNN TürkBeşiktaş'a yıldız futbolcularından iyi haberInquirer EntertainmentMiss Universe factions clash over 2027 host country claimsThe Jerusalem PostThree killed, several wounded following two attacks on Saudi Arabia's King Khalid airportESPN DeportesMessi entrenó con Inter Miami tras homenajePunchMother, daughter die in Anambra three-storey building collapseBollywood HungamaMeezaan Jafri headlines Killer Jeans' Genes of India campaignEl ComercioTrump niega un ataque contra Irán antes de las elecciones, pero el Pentágono prepara opciones de combateZDF heuteAktuelle Pressemitteilungen des ZDFStraits Times SportMaddinson's test return for Australia after cancer treatment ends in duckCollider10 Essential Anime Shows That Belong on Every Fan's Bucket ListBBC News BrasilQuem é Navi Pillay, sul-africana que ganhou o Nobel da Paz 2026 e julgou genocídio em Ruanda
The Daily Newsstand · Free, Always
Friday, October 9, 2026

SSD как кэш, HDD как постоянное хранилище: экспериментируем с кэшированием в bcachefs

Translate

Вы когда-нибудь задумывались над смыслом названия этой файловой системы? А между тем ключевая фича, с которой все начиналось, — это как раз кэширование. Изначально был bcache — прототип, на основе которого впоследствии вырос bcachefs. Вот как об этом рассказывает сам разработчик файловой системы Kent Overstreet:

Enter bcache, the prototype for bcachefs. When SSDs were first being introduced, they were from the beginning orders of magnitude faster than rotating disk - but expensive, so block layer caching was an obvious approach for using them effectively.

В этой статье мы наверстаем упущенное — познакомимся с этой фичей и узнаем, есть ли от нее профит.

Немного теории

Концепция кэширования не нова и уже реализована в RAID-контроллерах. Есть три режима работы кэша записи:

  • Write Back. Пишем в быстрый кэш и сразу отдаем сигнал ОС о завершенной операции записи. Не ждем завершения записи на медленный storage, находящийся за кэшем. Не все дается бесплатно: есть риск потери данных, если пропадет питание, питающее кэш. Для защиты от этого часто используются специальные аккумуляторы - BBU (Battery Backup Unit).

  • Write Through. Пишем в быстрый кэш, но отдаем сигнал о завершении операции записи только после того, как запись пройдет и в кэш, и в медленный storage.

  • Write Around. Пишем в медленный storage, без кэша.

В статье мы соберем в bcachefs конфигурацию, похожую на Write Back.

Подготовка окружения

Тестировать будем на виртуальной машине в облаке.

Кстати, повторять этот стенд у себя необязательно на голом железе — всю конфигурацию из четырех дисков с разными характеристиками можно собрать на ВМ любого облачного провайдера за несколько минут.

Если тоже хотите погонять caching или что-то еще на живом железе, а не только читать чужие бенчмарки — у нас в К2 Cloud сейчас действует грант до 30 000 ₽ на тестирование инфраструктуры для новых корпоративных клиентов: срок теста согласовывается индивидуально, от 3 недель до 60 дней, а бонус можно потратить на виртуальные машины, SSD/NVMe-хранилище и другие сервисы платформы.

Если подбирать диск под роль кэша (т.е. под --foreground_target), логично брать самый шустрый и с минимальной задержкой. У K2 Cloud это nv1 — выделенный физический NVMe SSD с производительностью до 256 тыс. IOPS и пропускной способностью до 1000 МиБ/с. За счет отказа от репликации вся производительность диска уходит на скорость, а не на избыточность — для кэша это то, что доктор прописал.

А пока вернемся к подготовке окружения.

CPU

4 vCPU

RAM

8 GiB

Объем

Тип диска

IOPS

Throughput

Блочное устройство

Разделы

mountpoint

Disk 1

20 GiB

st3

500

8 MiB/s

/dev/vda

/dev/vda1

/

Disk 2

256 GiB

st3

500

64 MiB/s

/dev/vdb

/dev/vdb1

/mnt/storage

Disk 3

64 GiB

io2

3200

500 MiB/s

/dev/vdc

/dev/vdc1

/mnt/storage

Disk 4

256 GiB

st3

500

64 MiB/s

/dev/vdd

/dev/vdd1

/mnt/storage_noncached_vdd

Здесь все просто: операционная система на отдельном диске (/dev/vda), чтобы не мешать тестам. Для хранения и тестов — один медленный диск (/dev/vdb) большого объема. Для кэша — быстрый (/dev/vdc), но небольшой. И еще один медленный диск (/dev/vdd) без кэша, чтобы сравнить производительность с первой парой.
Возьмем Ubuntu 26.04 с ядром 7.0.0-31-generic и установим на нее модуль bcachefs.

# стягиваем ключ разработчика
sudo install -d -m 0755 /etc/apt/keyrings
wget -qO- https://apt.bcachefs.org/apt.bcachefs.org.asc | sudo tee /etc/apt/keyrings/apt.bcachefs.org.asc > /dev/null
sudo chmod 0644 /etc/apt/keyrings/apt.bcachefs.org.asc
# Fingerprint: EA483B991020C72A8A5035ADA0620B5E0E01C1DD

# ставим его репу себе в apt
sudo tee /etc/apt/sources.list.d/apt.bcachefs.org.sources > /dev/null <<SOURCES
Types: deb deb-src
URIs: https://apt.bcachefs.org/$(. /etc/os-release && echo ${VERSION_CODENAME})/
Suites: bcachefs-tools-release
Components: main
Signed-By: /etc/apt/keyrings/apt.bcachefs.org.asc
SOURCES

# обновляем кэш и ставим нужный пакет
sudo apt update
sudo apt install bcachefs-tools

Поставим также утилиту для замера производительности.

sudo apt install fio

Осталось только подготовить файловые системы. Разбиваем диски.

sudo parted /dev/vdb mklabel gpt
sudo parted /dev/vdb mkpart ext2 1MiB 100%
sudo parted /dev/vdc mklabel gpt
sudo parted /dev/vdc mkpart ext2 1MiB 100%
sudo parted /dev/vdd mklabel gpt
sudo parted /dev/vdd mkpart ext2 1MiB 100%

Проверяем.

lsblk         

NAME   MAJ:MIN RM  SIZE RO TYPE MOUNTPOINTS
vda    253:0    0   20G  0 disk 
└─vda1 253:1    0   20G  0 part /
vdb    253:16   0  256G  0 disk 
└─vdb1 253:17   0  256G  0 part 
vdc    253:32   0   64G  0 disk 
└─vdc1 253:33   0   64G  0 part 
vdd    253:48   0  256G  0 disk 
└─vdd1 253:49   0  256G  0 part 

И наконец, форматируем.

sudo bcachefs format /dev/vd[bc]1 \
 --foreground_target /dev/vdc1 \
 --background_target /dev/vdb1 \
 --promote_target /dev/vdc1
sudo bcachefs format /dev/vdd1

Опция --foreground_target задает устройство для кэша записи, а --background_target — устройство для постоянного хранения, а --promote_target тоже указывает на кэш, но уже для чтения.

Интуитивно кажется, что таргеты логичнее задавать при монтировании файловой системы, но если попробовать это сделать, получим ошибку в dmesg:

sudo mount -t bcachefs -o foreground_target=/dev/vdc1,background_target=/dev/vdb1,promote_target=/dev/vdc1 /dev/vdb1:/dev/vdc1 /mnt/storage/
dmesg -T | tail -n 10
...
[Tue Sep 22 22:51:50 2026] bcachefs: bch2_parse_one_mount_opt() option foreground_target may no longer be specified at mount time; set via sysfs opts dir
[Tue Sep 22 22:51:50 2026] bcachefs: bch2_parse_one_mount_opt() option background_target may no longer be specified at mount time; set via sysfs opts dir
[Tue Sep 22 22:51:50 2026] bcachefs: bch2_parse_one_mount_opt() option promote_targetmay no longer be specified at mount time; set via sysfs opts dir

Похоже, раньше это так и было, но теперь таргеты сохраняются в superblock файловой системы прямо на диске и применяются автоматически при каждом следующем монтировании. В этом примере используется версия модуля 1.39.6.

Монтируем.

sudo mount -t bcachefs /dev/vdb1:/dev/vdc1 /mnt/storage/
sudo mount -t bcachefs /dev/vdd1 /mnt/storage_noncached_vdd
sudo lsblk -fs
NAME  FSTYPE   FSVER LABEL UUID                                 FSAVAIL FSUSE% MOUNTPOINTS
vda1  ext4     1.0         c248f645-8426-47a9-a343-3cfbe3c20c38   13.7G    25% /
└─vda                                                                          
vdb1  bcachefs 1.39        6aa33294-d16e-4104-80b9-53592f8df9f7  279.9G     3% /mnt/storage
└─vdb                                                                          
vdc1  bcachefs 1.39        6aa33294-d16e-4104-80b9-53592f8df9f7                
└─vdc     
vdd1  bcachefs 1.39        6ef11c96-2209-44d6-b093-5af2e88411ea  222.4G     3% /mnt/storage_noncached_vdd
└─vdd                                                                          
sudo bcachefs fs usage /mnt/storage/
Filesystem: 6aa33294-d16e-4104-80b9-53592f8df9f7
Size:             313615366656  
Used:               8428191744  
Online reserved:             0  


     undegraded  
1x:  8428191744  

cached:  8388608000  


Device label            Device  State          Size        Used  Use%  
(no label) (device 0):  vdb1    rw     272926502912  8388608000    3%  
(no label) (device 1):  vdc1    rw      68178407424  8428191744   15%  

Получившаяся конфигурация соответствует режиму Write Back во многих железных RAID-контроллерах: данные сначала пишутся на быстрое хранилище, а сигнал об успешной записи ОС получает сразу, не дожидаясь записи на низлежащее медленное хранилище.

Небольшим расхождением здесь является наличие опции --promote_target, которая не относится к политике Write Back (как следует из ее названия, она про запись). По поведению эта опция больше подходит на используемую в RAID-контроллерах Dell (PERC) фичу CacheCade, которая используется для повышения производительности случайных операций чтения для горячих (часто запрашиваемых) данных. Если верить документации Dell, она поддерживается только с сертифицированными SSD и только на контроллерах PERC H710P, H800, H810. Здесь же мы получаем ее без каких-либо сертифицированных дисков и проприетарных контроллеров — почти бесплатно.

Тестирование производительности

Для тестирования используем утилиту fio.

Подготовим некоторые данные, пусть это будет файл случайного содержимого размером 4 GiB.

sudo dd if=/dev/urandom of=/mnt/storage/file.raw bs=4k count=1000k

Сразу же посмотрим, как применяется кэширование.

sudo bcachefs fs usage -h /mnt/storage/
Filesystem: 6aa33294-d16e-4104-80b9-53592f8df9f7
Size:              292G  
Used:             7.85G  
Online reserved:      0  


     undegraded  
1x:       7.85G  

cached:  4.64G  


Pending reconcile:   data  metadata  
target:             3.17G         0  


Device label            Device  State   Size   Used  Use%  Leaving  
(no label) (device 0):  vdb1    rw      254G  4.64G    2%  
(no label) (device 1):  vdc1    rw     63.5G  7.85G   15%    3.17G    

Данные сразу записались в кэш. К моменту, когда запустили команду, в фоне уже шел reconcile (отправка данных из кэша в постоянное хранилище) — из 4 GiB отправлено уже 830 MiB (см. столбец 'Leaving').

Подождем немного и запустим команду снова.

Filesystem: 6aa33294-d16e-4104-80b9-53592f8df9f7
Size:              292G  
Used:             7.85G  
Online reserved:      0  


     undegraded  
1x:       7.85G  

cached:  7.51G  


Pending reconcile:  data  metadata  
target:             311M         0  


Device label            Device  State   Size   Used  Use%  Leaving  
(no label) (device 0):  vdb1    rw      254G  7.51G    3%  
(no label) (device 1):  vdc1    rw     63.5G  7.85G   15%     311M  

Как видно из вывода, объем кэшированных данных вырос до 7.51 GiB, а процесс reconcile почти завершил свою работу — из кэша в постоянное хранилище осталось отправить только 311 MiB. К началу тестирования весь файл уже будет и в кэше, и в постоянном хранилище.

Тест на последовательное чтение, IOPS

sudo touch /mnt/storage/file.raw
sudo fio --filename=/mnt/storage/file.raw --direct=1 --rw=read --bs=4k --ioengine=libaio --iodepth=256 --runtime=20 --numjobs=4 --time_based --group_reporting --name=iops-test-job --eta-newline=1 --readonly
iops-test-job: (groupid=0, jobs=4): err= 0: pid=2826: Tue Sep 22 23:23:27 2026
read: IOPS=2262, BW=9048KiB/s (9266kB/s)(181MiB/20461msec)

Для сравнения, такой же тест проведем на файловой системе без кэша.

sudo fio --filename=/mnt/storage_noncached_vdd/file.raw --direct=1 --rw=read --bs=4k --ioengine=libaio --iodepth=256 --runtime=20 --numjobs=4 --time_based --group_reporting --name=iops-test-job --eta-newline=1 --readonly
iops-test-job: (groupid=0, jobs=4): err= 0: pid=3505: Wed Sep 23 00:09:32 2026
read: IOPS=250, BW=1003KiB/s (1027kB/s)(23.5MiB/24013msec)

Тест на последовательное чтение, throughput

sudo fio --filename=/mnt/storage/file.raw --direct=1 --rw=read --bs=256k --ioengine=libaio --iodepth=64 --runtime=20 --numjobs=4 --time_based --group_reporting --name=throughput-test-job --eta-newline=1 --readonly
throughput-test-job: (groupid=0, jobs=4): err= 0: pid=2856: Tu e Sep 22 23:28:37 2026
read: IOPS=2243, BW=561MiB/s (588MB/s)(11.0GiB/20165msec)

Такой же тест на файловой системе без кэша:

sudo fio --filename=/mnt/storage_noncached_vdd/file.raw --direct=1 --rw=read --bs=256k --ioengine=libaio --iodepth=64 --runtime=20 --numjobs=4 --time_based --group_reporting --name=throughput-test-job --eta-newline=1 --readonly
throughput-test-job: (groupid=0, jobs=4): err= 0: pid=3530: Wed Sep 23 00:12:13 2026
read: IOPS=257, BW=64.3MiB/s (67.4MB/s)(1350MiB/21003msec)

Тест на случайное чтение, IOPS

sudo fio --filename=/mnt/storage/file.raw --direct=1 --rw=randread --bs=4k --ioengine=libaio --iodepth=256 --runtime=20 --numjobs=4 --time_based --group_reporting --name=iops-test-job --eta-newline=1 --readonly
iops-test-job: (groupid=0, jobs=4): err= 0: pid=3169: Tue Sep 22 23:50:23 2026
  read: IOPS=2128, BW=8514KiB/s (8718kB/s)(173MiB/20803msec)

Без кэша:

sudo fio --filename=/mnt/storage_noncached_vdd/file.raw --direct=1 --rw=randread --bs=4k --ioengine=libaio --iodepth=256 --runtime=20 --numjobs=4 --time_based --group_reporting --name=iops-test-job --eta-newline=1 --readonly
iops-test-job: (groupid=0, jobs=4): err= 0: pid=3551: Wed Sep 23 00:14:58 2026
read: IOPS=264, BW=1060KiB/s (1085kB/s)(21.7MiB/20977msec)

Тест на случайное чтение, throughput

sudo fio --filename=/mnt/storage/file.raw --direct=1 --rw=randread --bs=256k --ioengine=libaio --iodepth=64 --runtime=20 --numjobs=4 --time_based --group_reporting --name=throughput-test-job --eta-newline=1 --readonly
throughput-test-job: (groupid=0, jobs=4): err= 0: pid=2920: Tue Sep 22 23:36:03 2026
read: IOPS=1958, BW=490MiB/s (513MB/s)(9.87GiB/20638msec)

Без кэша:

sudo fio --filename=/mnt/storage_noncached_vdd/file.raw --direct=1 --rw=randread --bs=256k --ioengine=libaio --iodepth=64 --runtime=20 --numjobs=4 --time_based --group_reporting --name=throughput-test-job --eta-newline=1 --readonly
throughput-test-job: (groupid=0, jobs=4): err= 0: pid=3571: Wed Sep 23 00:16:09 2026
read: IOPS=221, BW=55.3MiB/s (58.0MB/s)(1169MiB/21129msec)

Тест на случайное чтение-запись, IOPS

sudo touch /mnt/storage/file_rw.raw
sudo fio --filename=/mnt/storage/file_rw.raw --size=4GiB --direct=1 --rw=randrw --bs=4k --ioengine=libaio --iodepth=256 --runtime=20 --numjobs=4 --time_based --group_reporting --name=iops-test-job --eta-newline=1
iops-test-job: (groupid=0, jobs=4): err= 0: pid=3288: Tue Sep 22 23:55:16 2026
read: IOPS=3048, BW=11.9MiB/s (12.5MB/s)(241MiB/20198msec)
write: IOPS=3066, BW=12.0MiB/s (12.6MB/s)(242MiB/20198msec); 0 zone resets

Без кэша:

sudo fio --filename=/mnt/storage_noncached_vdd/file_rw.raw --size=4GiB --direct=1 --rw=randrw --bs=4k --ioengine=libaio --iodepth=256 --runtime=20 --numjobs=4 --time_based --group_reporting --name=iops-test-job --eta-newline=1
iops-test-job: (groupid=0, jobs=4): err= 0: pid=3626: Wed Sep 23 00:20:37 2026
read: IOPS=266, BW=1064KiB/s (1090kB/s)(21.8MiB/20944msec)
write: IOPS=278, BW=1114KiB/s (1141kB/s)(22.8MiB/20944msec); 0 zone resets

Тест на случайное чтение-запись, throughput

sudo fio --filename=/mnt/storage/file_rw.raw --size=4GiB --direct=1 --rw=randrw --bs=64k --ioengine=libaio --iodepth=64 --runtime=20 --numjobs=4 --time_based --group_reporting --name=throughput-test-job --eta-newline=1
throughput-test-job: (groupid=0, jobs=4): err= 0: pid=3327: Tue Sep 22 23:58:07 2026
read: IOPS=1376, BW=86.0MiB/s (90.2MB/s)(1727MiB/20074msec)
write: IOPS=1393, BW=87.1MiB/s (91.3MB/s)(1749MiB/20074msec); 0 zone resets

Без кэша:

sudo fio --filename=/mnt/storage_noncached_vdd/file_rw.raw --size=4GiB --direct=1 --rw=randrw --bs=64k --ioengine=libaio --iodepth=64 --runtime=20 --numjobs=4 --time_based --group_reporting --name=throughput-test-job --eta-newline=1
throughput-test-job: (groupid=0, jobs=4): err= 0: pid=3651: Wed Sep 23 00:23:04 2026
read: IOPS=199, BW=12.5MiB/s (13.1MB/s)(258MiB/20700msec)
write: IOPS=210, BW=13.1MiB/s (13.8MB/s)(272MiB/20700msec); 0 zone resets

Сводка по результатам тестирования

Тест

/dev/vdb в качестве постоянного хранилища
+ /dev/vdc как кэш

/dev/vdd как постоянное хранилище, без кэша

последовательное чтение, IOPS

2262

250

последовательное чтение, throughput

561 MiB/s

64 MiB/s

случайное чтение, IOPS

2128

264

случайное чтение, throughput

490 MiB/s

55 MiB/s

случайное чтение-запись, IOPS

3048 read,
3066 write

266 read,
278 write

случайное чтение-запись, throughput

86 MiB/s read,
87 MiB/s write

12.5 MiB/s read,
13.1 MiB/s write

Во всех тестах побеждает вариант с кэшированием. Разумеется, в реальных условиях ситуация, когда все данные, в которые идет IO от приложения, находятся полностью в кэше (как у нас в тесте) в каждый момент времени, будет возникать редко. Итоговые цифры напрямую зависят от хранилища, используемого под кэш — его размера и производительности. Чем он больше, тем больше данных поместится в кэш целиком и тем быстрее они будут отдаваться, и наоборот. Поэтому воспринимать эти результаты следует как наглядную демонстрацию пользы кэширования в bcachefs, а не как референс.

Тестирование на прикладной нагрузке

Для более наглядной демонстрации посмотрим на показатели производительности в хранилище ключ-значение - RocksDB. Этот k/v store хранит в каталоге на файловой системе в виде множества файлов .SST. И в составе этого хранилища есть утилита бенчмарка - db_bench. 

Проведем с помощью нее три сравнительных теста:

  1. первичное заполнение базы случайными данными на ~70 GiB;

  2. чтение заполненной базы;

  3. обновление заполненной базы.

Подготовка окружения

В виде готовых бинарей найти не удалось, поэтому собираем вручную.

git clone https://github.com/facebook/rocksdb.git ; cd rocksdb/
sudo apt-get install libgflags-dev
sudo apt-get install libsnappy-dev
sudo apt-get install zlib1g-dev
sudo apt-get install libbz2-dev
sudo apt-get install liblz4-dev
sudo apt-get install libzstd-dev
make release

Подготовим директории для заполнения базы.

sudo mkdir -p /mnt/storage/rocksdb-bench
sudo mkdir -p /mnt/storage_noncached_vdd/rocksdb-bench

Заполнение базы случайными данными

Используем метод fillrandom для заполнения базы 25 млн. ключами. Размер ключа - 16 байт, размер значения ключа - 4096 байт. Такое заполнение даст нам примерно 98 GiB данных. В качестве показателя производительности будем использовать ops/sec - количество операций записи в секунду, где одна операция это запись одного ключа в RocksDB.

Без кэша

sudo ./db_bench --db="/mnt/storage_noncached_vdd/rocksdb-bench/" --benchmarks=fillrandom --num=25000000 --key_size=16 --value_size=4096 --compression_type=none --compression_ratio=1 --cache_size=268435456 --seed=17 --open_files=512

Initializing RocksDB Options from the specified file
Initializing RocksDB Options from command-line flags
Integrated BlobDB: blob cache disabled
RocksDB:    version 11.12.0
Date:       Tue Sep 29 22:44:47 2026
CPU:        4 * Intel(R) Xeon(R) Gold 6254 CPU @ 3.10GHz
CPUCache:   16384 KB
Keys:       16 bytes each (+ 0 bytes user-defined timestamp)
Values:     4096 bytes each (4096 bytes after compression)
Entries:    25000000
Prefix:    0 bytes
Keys per prefix:    0
RawSize:    98037.7 MB (estimated)
FileSize:   98037.7 MB (estimated)
Write rate: 0 bytes/second
Read rate: 0 ops/second
Compression: NoCompression
Compression sampling rate: 0
Memtablerep: SkipListFactory
Perf Level: 1
------------------------------------------------
Initializing RocksDB Options from the specified file
Initializing RocksDB Options from command-line flags
Integrated BlobDB: blob cache disabled
DB path: [/mnt/storage_noncached_vdd/rocksdb-bench/]
fillrandom   :     896.214 micros/op 1115 ops/sec 22405.356 seconds 25000000 operations;    4.4 MB/s

С кэшем

sudo ./db_bench --db="/mnt/storage/rocksdb-bench/" --benchmarks=fillrandom --num=25000000 --key_size=16 --value_size=4096 --compression_type=none --compression_ratio=1 --cache_size=268435456 --seed=17 --open_files=512

Initializing RocksDB Options from the specified file
Initializing RocksDB Options from command-line flags
Integrated BlobDB: blob cache disabled
RocksDB:    version 11.12.0
Date:       Wed Sep 30 11:05:48 2026
CPU:        4 * Intel(R) Xeon(R) Gold 6254 CPU @ 3.10GHz
CPUCache:   16384 KB
Keys:       16 bytes each (+ 0 bytes user-defined timestamp)
Values:     4096 bytes each (4096 bytes after compression)
Entries:    25000000
Prefix:    0 bytes
Keys per prefix:    0
RawSize:    98037.7 MB (estimated)
FileSize:   98037.7 MB (estimated)
Write rate: 0 bytes/second
Read rate: 0 ops/second
Compression: NoCompression
Compression sampling rate: 0
Memtablerep: SkipListFactory
Perf Level: 1
------------------------------------------------
Initializing RocksDB Options from the specified file
Initializing RocksDB Options from command-line flags
Integrated BlobDB: blob cache disabled
DB path: [/mnt/storage/rocksdb-bench/]
fillrandom   :     239.129 micros/op 4181 ops/sec 5978.235 seconds 25000000 operations;   16.4 MB/s

Результирующий объем данных на файловой системе немного отличается от рассчитанного db_bench, но все равно превышает размер кэша ( > 64 GiB ):

sudo du -sch /mnt/storage/rocksdb-bench/

69G    /mnt/storage/rocksdb-bench/
69G    total

sudo du -sch /mnt/storage_noncached_vdd/rocksdb-bench/

70G    /mnt/storage_noncached_vdd/rocksdb-bench/
70G    total

Как видно из результатов, заполнение RocksDB с кэшем bcachefs завершилось в 3.75 раз быстрее:

fillrandom: 896.214 micros/op 1115 ops/sec 22405.356 seconds 25000000 operations; 4.4 MB/s
fillrandom: 239.129 micros/op 4181 ops/sec 5978.235 seconds 25000000 operations; 16.4 MB/s

При этом, в отличие от предыдущего теста fio, мы намеренно использовали объем базы данных больше кэша, чтобы продемонстрировать более реалистичный сценарий, когда часть данных помещается в кэш, а часть не помещается.

Чтение заполненной базы данных

Используем метод readrandom, с 100000 случайных операций чтений. Минуем page cache (опция --use_direct_reads).

Без кэша:

sudo ./db_bench --db="/mnt/storage_noncached_vdd/rocksdb-bench/" --benchmarks=readrandom --use_existing_db=1 --use_existing_keys=1 --reads=100000 --threads=4 --key_size=16 --value_size=4096 --cache_size=268435456 --open_files=512 --use_direct_reads=1 --seed=17

Initializing RocksDB Options from the specified file
Initializing RocksDB Options from command-line flags
Integrated BlobDB: blob cache disabled
RocksDB:    version 11.12.0
Date:       Wed Sep 30 17:51:37 2026
CPU:        4 * Intel(R) Xeon(R) Gold 6254 CPU @ 3.10GHz
CPUCache:   16384 KB
Keys:       16 bytes each (+ 0 bytes user-defined timestamp)
Values:     4096 bytes each (2048 bytes after compression)
Entries:    1000000
Prefix:    0 bytes
Keys per prefix:    0
RawSize:    3921.5 MB (estimated)
FileSize:   1968.4 MB (estimated)
Write rate: 0 bytes/second
Read rate: 0 ops/second
Compression: Snappy
Compression sampling rate: 0
Memtablerep: SkipListFactory
Perf Level: 1
------------------------------------------------
DB path: [/mnt/storage_noncached_vdd/rocksdb-bench/]
readrandom   :   41835.943 micros/op 95 ops/sec 4188.298 seconds 400000 operations;    0.4 MB/s (100000 of 100000 found)
Microseconds per read:
Count: 400000 Average: 41835.9452  StdDev: 17700.56
Min: 13  Median: 40913.7095  Max: 276074
Percentiles: P50: 40913.71 P75: 55302.70 P99: 100871.02 P99.9: 118833.33 P99.99: 217111.11

С кэшем:

sudo ./db_bench --db="/mnt/storage/rocksdb-bench/" --benchmarks=readrandom --use_existing_db=1 --use_existing_keys=1 --reads=100000 --threads=4 --key_size=16 --value_size=4096 --cache_size=268435456 --open_files=512 --use_direct_reads=1 --seed=17

Initializing RocksDB Options from the specified file
Initializing RocksDB Options from command-line flags
Integrated BlobDB: blob cache disabled
RocksDB:    version 11.12.0
Date:       Wed Sep 30 16:05:43 2026
CPU:        4 * Intel(R) Xeon(R) Gold 6254 CPU @ 3.10GHz
CPUCache:   16384 KB
Keys:       16 bytes each (+ 0 bytes user-defined timestamp)
Values:     4096 bytes each (2048 bytes after compression)
Entries:    1000000
Prefix:    0 bytes
Keys per prefix:    0
RawSize:    3921.5 MB (estimated)
FileSize:   1968.4 MB (estimated)
Write rate: 0 bytes/second
Read rate: 0 ops/second
Compression: Snappy
Compression sampling rate: 0
Memtablerep: SkipListFactory
Perf Level: 1
------------------------------------------------
DB path: [/mnt/storage/rocksdb-bench/]
readrandom   :    5396.803 micros/op 736 ops/sec 542.883 seconds 400000 operations;    2.9 MB/s (100000 of 100000 found)
Microseconds per read:
Count: 400000 Average: 5396.8041  StdDev: 5316.71
Min: 8  Median: 3729.7822  Max: 192307
Percentiles: P50: 3729.78 P75: 6959.66 P99: 24398.90 P99.9: 51431.30 P99.99: 115142.86

Случайное чтение с кэшем bcachefs показывает прирост производительности в 7.74 раза (736 ops/sec против 95 ops/sec).

Обновление заполненной базы

Используем метод overwrite, с 50 000 операций перезаписи.

Без кэша

sudo ./db_bench --db="/mnt/storage_noncached_vdd/rocksdb-bench/" --benchmarks=overwrite --use_existing_db=1 --use_existing_keys=1 --writes=50000 --threads=1 --key_size=16 --value_size=4096 --compression_type=none --compression_ratio=1 --cache_size=268435456 --open_files=512 --sync=1 --seed=17

Initializing RocksDB Options from the specified file
Initializing RocksDB Options from command-line flags
Integrated BlobDB: blob cache disabled
RocksDB:    version 11.12.0
Date:       Wed Sep 30 19:58:26 2026
CPU:        4 * Intel(R) Xeon(R) Gold 6254 CPU @ 3.10GHz
CPUCache:   16384 KB
Keys:       16 bytes each (+ 0 bytes user-defined timestamp)
Values:     4096 bytes each (4096 bytes after compression)
Entries:    1000000
Prefix:    0 bytes
Keys per prefix:    0
RawSize:    3921.5 MB (estimated)
FileSize:   3921.5 MB (estimated)
Write rate: 0 bytes/second
Read rate: 0 ops/second
Compression: NoCompression
Compression sampling rate: 0
Memtablerep: SkipListFactory
Perf Level: 1
------------------------------------------------
DB path: [/mnt/storage_noncached_vdd/rocksdb-bench/]
overwrite    :    4098.578 micros/op 243 ops/sec 204.929 seconds 50000 operations;    1.0 MB/s
Microseconds per write:
Count: 50000 Average: 4098.5796  StdDev: 6168.40
Min: 760  Median: 3722.2553  Max: 855061
Percentiles: P50: 3722.26 P75: 4138.38 P99: 6467.21 P99.9: 9437.38 P99.99: 170000.00

С кэшем

sudo ./db_bench --db="/mnt/storage/rocksdb-bench/" --benchmarks=overwrite --use_existing_db=1 --use_existing_keys=1 --writes=50000 --threads=1 --key_size=16 --value_size=4096 --compression_type=none --compression_ratio=1 --cache_size=268435456 --open_files=512 --sync=1 --seed=17

Initializing RocksDB Options from the specified file
Initializing RocksDB Options from command-line flags
Integrated BlobDB: blob cache disabled
RocksDB:    version 11.12.0
Date:       Wed Sep 30 20:50:38 2026
CPU:        4 * Intel(R) Xeon(R) Gold 6254 CPU @ 3.10GHz
CPUCache:   16384 KB
Keys:       16 bytes each (+ 0 bytes user-defined timestamp)
Values:     4096 bytes each (4096 bytes after compression)
Entries:    1000000
Prefix:    0 bytes
Keys per prefix:    0
RawSize:    3921.5 MB (estimated)
FileSize:   3921.5 MB (estimated)
Write rate: 0 bytes/second
Read rate: 0 ops/second
Compression: NoCompression
Compression sampling rate: 0
Memtablerep: SkipListFactory
Perf Level: 1
------------------------------------------------
DB path: [/mnt/storage/rocksdb-bench/]
overwrite    :    1033.723 micros/op 967 ops/sec 51.686 seconds 50000 operations;    3.8 MB/s
Microseconds per write:
Count: 50000 Average: 1033.7239  StdDev: 326.13
Min: 710  Median: 1065.4883  Max: 29081
Percentiles: P50: 1065.49 P75: 1202.16 P99: 1934.40 P99.9: 3770.00 P99.99: 12881.82

967 ops/sec с кэшем bcachefs против 243 ops/sec без кэша - разница составляет почти 4 раза.

Итоги

  • Если у вас уже где-то работает bcachefs на медленном хранилище (например, HDD), но вы по какой-то причине не используете кэширование, самое время это исправить — даже небольшой SSD способен дать огромную прибавку к производительности.

  • Поскольку реализация полностью программная, вам не нужно завязываться на аппаратные возможности storage-контроллера.

  • В прикладной нагрузке (RocksDB с объемом базы больше объема кэша) использование кэша bcachefs показало существенный рост производительности: примерно в 3.75 раз быстрее запись случайных пар ключ-значение и до 7.74 раз быстрее чтение случайных пар ключ-значение.

А если тема производительности зашла, 20 октября у нас будет онлайн-митап по теме – сравним nv1 с gp2 и io2 в синтетических тестах на fio (IOPS, latency, throughput), покажем, как устроен сетевой нереплицируемый диск изнутри, поднимем PostgreSQL под нагрузкой и разберем, что происходит при отказе диска или узла. О том, как вписаться на этот движ — по ссылке. Присоединяйтесь!

View the original on Хабр →

KioskNews shows a cleaned-up reading view extracted from the publisher’s page — the original always lives on their site, not ours.