copy-on-write B-деревья вместо журнала — снапшоты почти бесплатны, но RAID5/6 всё ещё «не для прода» спустя больше десяти летcopy-on-write B-trees instead of a journal — snapshots are nearly free, but RAID5/6 is still "not for production" over a decade later
Btrfs не журналирует изменения, как ext4 — вместо этого она никогда не перезаписывает данные на месте: любое изменение блока создаёт новую копию где-то ещё, а старая остаётся нетронутой, пока на неё есть ссылки. Это устраняет целый класс проблем согласованности, которые journaling только смягчает, и делает снапшоты файловой системы операцией на несколько миллисекунд вместо полного копирования. Тот же механизм даёт сквозные чексуммы данных и метаданных — но применить его к RAID5/6 оказалось труднее, чем к обычному тому: проблема write hole в Btrfs официально не решена и сегодня.Btrfs doesn't journal changes like ext4 — instead, it never overwrites data in place: any block modification creates a new copy somewhere else, while the old one stays untouched as long as something still references it. This eliminates an entire class of consistency problems that journaling only mitigates, and turns a filesystem snapshot into a few-millisecond operation instead of a full copy. The same mechanism gives end-to-end data and metadata checksums — but applying it to RAID5/6 turned out harder than to a plain volume: the write hole problem in Btrfs is still officially unresolved today.
Btrfs (B-tree FS) спроектирована вокруг одной центральной идеи — copy-on-write (CoW) для всего: и данных, и метаданных. Вместо разделения на «место для данных» и «журнал транзакций», как в ext4, вся файловая система (кроме самого суперблока) представлена набором B-деревьев, и любое изменение узла дерева физически пишется в новый блок, а не поверх старого. Из этого одного решения следует почти всё остальное: дешёвые снапшоты (общий CoW между оригиналом и копией), встроенный RAID без отдельного mdadm, и сквозные чексуммы (раз блок всё равно копируется целиком при изменении, посчитать и сохранить его хэш почти бесплатно).Btrfs (B-tree FS) is designed around one central idea — copy-on-write (CoW) for everything, both data and metadata. Instead of splitting into "data area" and "transaction journal" like ext4, the entire filesystem (except the superblock itself) is represented as a set of B-trees, and any change to a tree node is physically written to a new block rather than over the old one. Almost everything else follows from this single decision: cheap snapshots (shared CoW between the original and the copy), built-in RAID with no separate mdadm, and end-to-end checksums (since a block gets copied wholesale on change anyway, computing and storing its hash is nearly free).
| параметрparameter | ext4 | Btrfs |
|---|---|---|
| защита от сбояcrash protection | журнал метаданных (JBD2)metadata journal (JBD2) | copy-on-write — старые данные не перезаписываются, пока новые не подтвержденыcopy-on-write — old data isn't overwritten until the new data is confirmed |
| чексуммы данныхdata checksums | нет (только metadata_csum для метаданных)no (only metadata_csum for metadata) | да, сквозные для данных и метаданныхyes, end-to-end for both data and metadata |
| снапшотыsnapshots | нет (нужен LVM снизу)no (needs LVM underneath) | встроены, почти бесплатны за счёт CoWbuilt in, nearly free thanks to CoW |
| RAID | нет (нужен mdadm/LVM снизу)no (needs mdadm/LVM underneath) | встроен на уровне ФС (0/1/1c3/1c4/10; 5/6 не для прода)built into the filesystem (0/1/1c3/1c4/10; 5/6 not for production) |
| изменение размераresizing | online только увеличение; уменьшение офлайнonline growth only; shrinking requires offline | online в обе стороны (grow и shrink)online both ways (grow and shrink) |
| зрелость / стабильностьmaturity / stability | многолетний промышленный стандартa multi-year industry standard | стабильна для одиночного тома/RAID1, но с историей нареканий на отдельные фичиstable for single-device/RAID1, but with a history of complaints about specific features |
Ключевое отличие от ext4 видно уже на уровне одной операции записи. В ext4 изменение файла обновляет existующие блоки на месте (журнал лишь описывает это изменение для восстановления после сбоя); в Btrfs каждое изменение блока — данных или метаданных — создаёт новую физическую копию, а указатели родительских узлов дерева переписываются, чтобы указывать на неё:The key difference from ext4 is visible at the level of a single write. In ext4, modifying a file updates the existing blocks in place (the journal just describes the change for crash recovery); in Btrfs, every block change — data or metadata — creates a new physical copy, and the parent tree nodes' pointers are rewritten to point at it:
Btrfs хранит почти всё как набор B-деревьев, а не как жёстко зашитые структуры вроде block group ext4. Работа с реальным диском требует различать логический адрес (используется внутри всех деревьев файловой системы) и физический (реальное смещение байт на конкретном устройстве) — это разделение и делает возможным RAID на уровне самой ФС:Btrfs stores almost everything as a set of B-trees rather than hard-wired structures like ext4's block groups. Working with the real disk requires distinguishing a logical address (used inside all the filesystem's trees) from a physical one (a real byte offset on a specific device) — and this split is exactly what makes RAID possible at the filesystem level itself:
Снапшот подраздела (subvolume) — прямое следствие этой же архитектуры, а не отдельная реализованная поверх ФС фича. Создание снапшота — это создание нового корня fs tree, который в момент создания указывает на те же самые узлы, что и оригинал (то есть, буквально, тот же самый extent tree ниже по дереву). Никакого копирования данных не происходит:A subvolume snapshot is a direct consequence of the same architecture, not a separate feature bolted on top of the filesystem. Creating a snapshot means creating a new fs tree root that, at the moment of creation, points at the exact same nodes as the original (literally the same extent tree further down). No data copying happens:
| моментmoment | что происходит с блокамиwhat happens to the blocks |
|---|---|
| btrfs subvolume snapshot | создаётся новый корень fs tree, указывающий на всё то же дерево — общие данные ни разу не копируются; операция занимает миллисекунды независимо от размера подразделаa new fs tree root is created pointing at the exact same tree — shared data is never copied; the operation takes milliseconds regardless of the subvolume's size |
| файл читается из снапшотаa file is read from the snapshot | читаются те же физические блоки, что и из оригинала — оба указывают на один и тот же extentthe same physical blocks are read as from the original — both point at the same extent |
| файл изменяется в оригинале или в снапшотеa file is modified in the original or in the snapshot | срабатывает CoW: изменяемый блок копируется в новое место, только в этом дереве обновляется указатель — второе дерево продолжает видеть старую версию блокаCoW kicks in: the block being changed is copied to a new location, only that tree's pointer is updated — the other tree keeps seeing the old version of the block |
Та же самая механика работает при cp --reflink: создаётся новый inode, ссылающийся на существующие extent-ы оригинала, вместо физического копирования данных — с точки зрения пользователя получается «копия файла», созданная почти мгновенно и без расхода места, пока обе версии идентичны.The same mechanics power cp --reflink: a new inode is created referencing the original's existing extents instead of physically copying the data — from the user's point of view, it looks like a "file copy" created almost instantly and using no extra space, as long as both versions stay identical.
Поскольку CoW всё равно копирует блок целиком при любом изменении, добавить к нему контрольную сумму почти ничего не стоит — Btrfs хранит чексумму (по умолчанию CRC32C, доступны более сильные алгоритмы с ядра 5.5) в отдельном checksum tree и проверяет её при каждом чтении:Since CoW copies a block wholesale on any change anyway, adding a checksum to it costs almost nothing — Btrfs stores a checksum (CRC32C by default, stronger algorithms available since kernel 5.5) in a separate checksum tree and verifies it on every read:
btrfs scrub — фоновая проверка вообще всех данных и метаданных на всём томе, а не только тех, что реально читаются приложениями; рекомендуется запускать периодически именно для того, чтобы поймать бит-рот заранее, а не в момент, когда понадобился редко используемый файлbtrfs scrub — a background check of literally all data and metadata on the whole volume, not just what applications happen to read; recommended to run periodically precisely to catch bit rot early, not at the moment a rarely used file is finally needed| командаcommand | что происходитwhat happens |
|---|---|
| btrfs subvolume create /mnt/@home | создаёт независимый подраздел внутри тома — можно монтировать отдельно, снапшотить отдельно от других подразделов (типичная схема: отдельные subvolume для @, @home, @snapshots)creates an independent subvolume inside the volume — can be mounted separately, snapshotted independently of other subvolumes (a common layout: separate subvolumes for @, @home, @snapshots) |
| btrfs subvolume snapshot /mnt/@ /mnt/@snapshots/pre-update | создаёт снапшот за миллисекунды — стандартная практика перед обновлением системы: если что-то сломается, откат — это смена подраздела при загрузке, а не восстановление из бэкапаcreates a snapshot in milliseconds — standard practice before a system update: if something breaks, rollback is switching the boot subvolume, not restoring from a backup |
| cp --reflink=always src dst | создаёt лёгкую копию файла, разделяющую физические extent-ы с оригиналом, пока данные не разойдутся — почти мгновенно даже для больших файловcreates a lightweight copy of a file sharing physical extents with the original until the data diverges — nearly instant even for large files |
| btrfs scrub start /mnt | запускает фоновую проверку чексумм всех данных на томе; на избыточных профилях (RAID1/DUP) автоматически чинит найденные несовпадения из второй копииstarts a background checksum verification of all data on the volume; on redundant profiles (RAID1/DUP), automatically repairs found mismatches from the second copy |
| btrfs filesystem resize +10G /mnt | увеличивает том на лету без размонтирования; тот же инструмент умеет и уменьшать размер онлайн — операция, которой у ext4 нет вовсеgrows the volume on the fly without unmounting; the same tool can also shrink it online — an operation ext4 doesn't have at all |
| btrfs device add /dev/sdb /mnt && btrfs balance start /mnt | добавляет диск к существующему тому и перераспределяет данные по новому набору устройств — расширение массива без полного пересоздания, недоступное классическому RAID+ФС поверх негоadds a disk to an existing volume and redistributes data across the new set of devices — expanding the array without a full recreation, unavailable to classic RAID+filesystem-on-top |
Документация проекта прямо называет реализацию RAID5/6 содержащей «недостатки проектирования и реализации» и рекомендует использовать её только для оценки/тестирования, не в проде. Ключевая нерешённая проблема — классический write hole: при сбое питания посреди записи блока данных и его parity-блока для RAID5/6 они могут разойтись, а сама Btrfs (в отличие от, например, ZFS RAID-Z) не даёт по этому конкретному сценарию 100% гарантии восстановления. Даже официальный man рекомендует держать метаданные на RAID1/RAID1c3, даже если данные лежат на RAID5/6.the project's documentation explicitly describes the RAID5/6 implementation as having "design and implementation deficiencies" and recommends it only for evaluation/testing, not production. The key unresolved issue is the classic write hole: a power failure mid-write of a data block and its parity block for RAID5/6 can leave them out of sync, and Btrfs itself (unlike, say, ZFS RAID-Z) doesn't give a 100% recovery guarantee for this specific scenario. Even the official man page recommends keeping metadata on RAID1/RAID1c3 even when data sits on RAID5/6.
Пространство выделяется chunk tree блоками ~1 ГиБ под данные и отдельно под метаданные, и переиспользование этих chunk-ов происходит не мгновенно — классическая жалоба «df показывает мало места, а реально файлов почти нет» почти всегда означает, что нужен btrfs filesystem usage вместо обычного df, и иногда явный btrfs balance для пересборки полупустых chunk-ов.space is allocated by the chunk tree in ~1 GiB blocks for data and separately for metadata, and reusing those chunks isn't instantaneous — the classic complaint "df shows little free space but there's barely any files" almost always means btrfs filesystem usage is needed instead of plain df, and sometimes an explicit btrfs balance to consolidate half-empty chunks.
Снапшот живёт на том же физическом томе, что и оригинал — он защищает от «случайно удалил файл» или «обновление сломало систему», но не от отказа самого диска. Полноценная защита требует либо избыточного RAID-профиля под снапшотами, либо btrfs send/receive для отправки снапшота на физически другое устройство/машину.a snapshot lives on the same physical volume as the original — it protects against "accidentally deleted a file" or "an update broke the system", but not against the disk itself failing. Real protection requires either a redundant RAID profile underneath the snapshots, or btrfs send/receive to ship the snapshot to a physically separate device/machine.