Дедупликация BTRFS

Несколько недель назад я начал новый эксперимент по работе с BTRFS. На этот раз целью стала оффлайн-дедупликация – довольно сложный и неоднозначный процесс для файловых систем на основе COW. Ближайший конкурент BTRFS, ZFS, имеет онлайн-вид дедупликации, встроенный в ФС. В таком случае по умолчанию требуются большие объёмы RAM. Также дедуп в онлайне увеличивает задержку при записи данных.

В BTRFS изначально было принято решение отказаться от идеи онлайн дедупликации и надеяться на лучшее. А задачу выявления дубликатов отдать на откуп внешним инструментам, которые пользователи буду сами использовать по необходимости.

Поработал я с двумя такими инструментами: duperemove и BEES. Сегодня коротко расскажу про работу с BEES, т.к. он выглядит для меня куда более интересным и (концептуально) чуть более простым инструментом, нежели duperemove.

Мой опыт с BEES был на версии 0.10. На днях (22 июня) вышла версия 0.11. Теперь BEES опирается на более свежие ядра Linux, минимальное рекомендуемая версия ядра – 5.7. Из LTS это будет версия 6.1, как и стандартная у Debian Bookworm.

Не буду останавливаться на деталях того, как BEES работает, это замечательно расписано разработчиком в файле docs/how-it-works.md в репозитории на GitHub. Я же продолжу коротким практическом гайдом: как запускать и что смотреть.

Первым делом нужно выкачать репу с GitHub и перейти в новую папку.

$ git clone https://github.com/Zygo/bees.git

Cloning into 'bees'...
remote: Enumerating objects: 4594, done.
remote: Counting objects: 100% (1203/1203), done.
remote: Compressing objects: 100% (575/575), done.
remote: Total 4594 (delta 689), reused 754 (delta 610), pack-reused 3391 (from 2)
Receiving objects: 100% (4594/4594), 1.37 MiB | 4.41 MiB/s, done.
Resolving deltas: 100% (3134/3134), done.

$ cd bees/

Коммиты в основной ветке не являются релизными, поэтому смотрим на теги.

$ git tag | sort -rV | head

v0.11-rc4
v0.11-rc3
v0.11-rc2
v0.11-rc1
v0.11
v0.10
v0.9.3
v0.9.2
v0.9.1
v0.9

Версия 0.11 – последняя, переходим на неё, собираем программу и устанавливаем.

$ git checkout v0.11

[...]

$ sudo apt install -y \
    build-essential \
    btrfs-progs \
    markdown \
    pkg-config \
    systemd-dev

[...]

$ make

[...]

$ sudo make install

[...]
install -Dm755 bin/bees /usr/lib/bees/bees
install -Dm755 scripts/beesd /usr/sbin/beesd
install -Dm644 scripts/beesd.conf.sample /etc/bees/beesd.conf.sample
install -Dm644 scripts/beesd@.service /lib/systemd/system/beesd@.service

Как видно, BEES установил бинарник bees, скрипт beesd и конфиг сервиса. На этом этапе нужно сформировать конфигурацию для ФС. Пример конфига с базовыми комментариями BEES положил в /etc/bees/beesd.conf.sample. Он полезный, но многословный, я приведу пример своего .conf. Конфиги можно называть как захочется, у меня он называется data.conf, как и BTRFS раздел.

$ cat /etc/bees/data.conf

UUID=bc574c75-0f22-45d1-b43d-13fdb423450e
OPTIONS="--strip-paths --verbose 7 --thread-count 4"
DB_SIZE=$((1*1024*1024*1024)) # 1G in bytes

Мне потребовалось установить всего 3 параметра (больше в docs/options.md):

Можно указать любой объём DB_SIZE, нужно только учитывать, что файл этого объёма будет постоянно находится в оперативной памяти при работе BEES.

Изменение DB_SIZE после того, как BEES уже начал сканировать ФС, приведут к новому сканированию с нуля! Будьте внимательны!

После того, как Вы собрали свой .conf и положили в /etc/bees/, запустить BEES можно через systemctl, а наблюдать за работой через journalctl. Интересная особенность – для сервиса требуется указывать UUID раздела BTRFS.

$ sudo systemctl start beesd@bc574c75-0f22-45d1-b43d-13fdb423450e

$ sudo journalctl -o cat -f -u beesd@bc574c75-0f22-45d1-b43d-13fdb423450e

2025-06-27 15:23:12 18211.18211<7> bees: context constructed
2025-06-27 15:23:12 18211.18211<7> bees: Parsing option 'no-timestamps'
2025-06-27 15:23:12 18211.18211<7> bees: Parsing option 'strip-paths'
2025-06-27 15:23:12 18211.18211<7> bees: Parsing option 'verbose'
2025-06-27 15:23:12 18211.18211<5> bees: log level set to 7
bees[18211]: setting worker thread pool maximum size to 4
bees[18211]: setting throttle factor to 0
bees[18211]: setting root path to '/run/bees/mnt/bc574c75-0f22-45d1-b43d-13fdb423450e'
bees[18211]: Starting bees main loop...
crawl_writeback[18243]: Using fsync on btrfs because kernel version is 6.12
[...]

В логах можно получать статус по состоянию, но проще смотреть в .status файл. BEES обновляет этот файл в директории /run/bees. В .status есть очень много информации и читать её тяжело. Для упрощения задачи нас интересует таблица в самом конце файла, после строки с PROGRESS:. sed, как и всегда, выручит.

$ sudo sed -n '/PROGRESS:/,$ p' \
    /run/bees/bc574c75-0f22-45d1-b43d-13fdb423450e.status

PROGRESS:
extsz   datasz  point gen_min gen_max this cycle start tm_left   next cycle ETA
----- -------- ------ ------- ------- ---------------- ------- ----------------
  max   5.039T 004263       0  556061 2025-06-27 16:54  7h 47m 2025-06-28 00:43
  32M    1.53T 002409       0  556061 2025-06-27 16:54 13h 48m 2025-06-28 06:44
   8M 368.251G 003183       0  556061 2025-06-27 16:54 10h 26m 2025-06-28 03:22
   2M  84.163G 001566       0  556061 2025-06-27 16:54 21h 15m 2025-06-28 14:11
 512K  89.955G 000899       0  556061 2025-06-27 16:54  1d 13h 2025-06-29 05:58
 128K   1.671G 002137       0  556061 2025-06-27 16:54 15h 33m 2025-06-28 08:30
total   7.101T        gen_now  556066                  updated 2025-06-27 16:56

Цель здесь – чтобы значения gen_max во всех строках сошлись со значением в строке total, а в колонке point на всех строках было idle вместо цифр. Соблюдение этих условий означает, что раздел ФС был полностью обработан BEES.

Вот так, для сравнения, выглядит .status для полностью просканированной ФС.

$ sudo sed -n '/PROGRESS:/,$ p' \
    /run/bees/bc574c75-0f22-45d1-b43d-13fdb423450e.status

PROGRESS:
extsz  datasz point gen_min gen_max this cycle start tm_left   next cycle ETA
----- ------- ----- ------- ------- ---------------- ------- ----------------
  max   5.69T  idle  555955  555957 2025-06-27 15:59       -                -
  32M  1.011T  idle  555955  555957 2025-06-27 15:59       -                -
   8M 307.66G  idle  555955  555957 2025-06-27 15:59       -                -
   2M 55.148G  idle  555955  555957 2025-06-27 15:59       -                -
 512K   37.6G  idle  555955  555957 2025-06-27 15:59       -                -
 128K  8.969G  idle  555955  555957 2025-06-27 15:59       -                -
total  7.101T       gen_now  555957                  updated 2025-06-27 15:59

Выключается BEES как и обычный сервис в systemctl.

$ sudo systemctl stop beesd@bc574c75-0f22-45d1-b43d-13fdb423450e

На этом основные элементы работы с BEES заканчиваются.

В целом, я не скажу, что дедупликация высвободила мне огромное количество места. Нет, скорее наоборот – дедуп привёл к росту метаданных, а на первых этапах BEES и вовсе съел несколько сотен гигабайт, часть которых высвободил только подходя к финалу полного сканирования раздела BTRFS. Такая себе оптимизация…

Основной эффект от BEES, судя по всему, должен наблюдаться, если использовать его постоянно и перед созданием read-only снимков BTRFS. Подтвердить это объективными данными мне сложно. Но над экспериментом стоит подумать :)

Журнал изменений

26 января 2026 г.: добавил pkg-config и systemd-dev в список пакетов для установки.

Если Вы хотите обсудить содержание заметки, задать вопросы или предложить изменения, то со мной можно связаться в Telegram