Вы когда‑нибудь задумывались над смыслом названия этой файловой системы? А между тем ключевая фича, с которой все начиналось, — это как раз кэширование. Изначально был 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.

Привет, Хабр! Меня зовут Никита Глушаев, я – старший инженер в K2 Cloud, и в этой статье мы с вами наверстаем упущенное — познакомимся с этой фичей и узнаем, есть ли от нее профит.

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

Концепция кэширования не нова и уже реализована в 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, с 100 000 случайных операций чтений. Минуем 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 под нагрузкой и разберем, что происходит при отказе диска или узла. О том, как вписаться на этот движ — по ссылке. Присоединяйтесь!