ZFS на FreeBSD і Linux: скільки RAM потрібно VPS
ZFS дає checksums, snapshots, send/receive і compression, але ARC займає RAM. Дізнайтеся, як оцінити витрати пам’яті на VPS із 2 або 4 GB.
Що дає ZFS і яких ресурсів він потребує
ZFS у FreeBSD і Linux тепер використовує одну кодову базу — OpenZFS, тому набір функцій в обох системах однаковий. Сервер із ZFS отримує контрольні суми даних, миттєві знімки, які не займають додаткового місця, доки дані не змінюються, реплікацію за допомогою zfs send і стиснення, яке вмикається встановленням однієї властивості. Водночас ZFS потребує пам’яті: ARC (adaptive replacement cache) за замовчуванням використовує значну частину RAM, а на VPS (virtual private server) із 2 GB або 4 GB саме цієї пам’яті може потребувати ваш застосунок.
У цьому посібнику ZFS розглядається на орендованому VPS з одним або двома віртуальними дисками, а не на системі зберігання на сорок дискових відсіків. Функції, які залишаються корисними в таких умовах, варті вашої уваги. Про обмеження, які в таких умовах проявляються, варто знати до створення pool.
OpenZFS у FreeBSD і Linux: одна кодова база, два способи пакування
FreeBSD включає ZFS до базової системи з FreeBSD 7.0, випущеної у 2008 році, спочатку як експериментальну функцію. Починаючи з OpenZFS 2.0 у грудні 2020 року, FreeBSD і Linux збираються з одного дерева вихідного коду, тому zfs і zpool працюють однаково в обох системах, а пул, створений в одній системі, можна імпортувати в іншій.
Причина, через яку ZFS є пакетом у Linux і частиною базової системи у FreeBSD, полягає в ліцензуванні. OpenZFS поширюється за CDDL (common development and distribution license). Ядро Linux поширюється за GPL (general public license) версії 2. Проєкт ядра вважає ці ліцензії несумісними, тому код ZFS не об’єднано з основною гілкою Linux, а кожен дистрибутив сам вирішує, як його постачати. У FreeBSD такого конфлікту немає, тому ZFS просто доступний у системі. Практичний висновок простий: відрізняється лише спосіб пакування, і вам не потрібно ставати на чийсь бік.
SSD Nodes не пропонує образи FreeBSD, тому на сервері, орендованому тут, застосовується Linux-частина цього посібника. Якщо ви використовуєте FreeBSD в іншому місці, сервер FreeBSD отримує ZFS без потреби збирати модуль і без необхідності переживати оновлення ядра.
Встановлення ZFS і створення пулу
В Ubuntu модуль входить до складу пакетів ядра, тому потрібно встановити лише команди.
sudo apt update
sudo apt install -y zfsutils-linux
zfs versionzfs version виводить два рядки: версію userland і версію модуля ядра. Якщо виведено лише один рядок, модуль не завантажився. Пакет міститься в компоненті universe, який образи Ubuntu Server увімкнено за замовчуванням. Якщо apt не може знайти пакет, спочатку виконайте sudo add-apt-repository universe.
В Debian пакети містяться в компоненті contrib, а модуль збирається на вашій машині за допомогою DKMS (dynamic kernel module support). Додайте contrib до рядка Components: у файлі /etc/apt/sources.list.d/debian.sources, виконайте sudo apt update, а потім:
sudo apt install -y linux-headers-$(dpkg --print-architecture) zfs-dkms zfsutils-linuxПід час встановлення модуль компілюється, а система виводить Building initial module for 6.12.0-.... Це займає кілька хвилин. Врахуйте наслідки: після кожного оновлення ядра модуль потрібно збирати знову. Якщо збірка завершиться помилкою, пул не буде імпортовано, доки ви не усунете проблему.
У FreeBSD нічого встановлювати не потрібно. Увімкніть службу та запустіть її.
sysrc zfs_enable=YES
service zfs startТепер створіть пул. Спочатку перевірте стабільні шляхи до пристроїв, оскільки /dev/vdb призначається в порядку виявлення пристроїв і може змінитися після підключення іншого тому.
ls -l /dev/disk/by-id/
sudo zpool create -o ashift=12 tank /dev/disk/by-id/virtio-abc123def456
zpool status tankzpool status має вивести state: ONLINE із вашим пристроєм у розділі tank. ashift=12 встановлює мінімальний розмір блока пулу на 4 KiB. Це відповідає сучасним SSD і не може бути змінено після створення пулу.
Більшість орендованих образів завантажується з кореневої файлової системи ext4, тому ZFS тут використовується як пул даних на другому томі, а не як коренева файлова система. Переконайтеся, що це саме потрібний пристрій, перш ніж створювати на ньому пул, оскільки підтвердження придбаного вами NVMe-диска займає одну хвилину, а відновлення після помилки — цілий день.
Контрольні суми виправляють помилки лише за наявності надлишковості в пулі
Кожен блок, який записує ZFS, містить контрольну суму, а під час кожного читання вона перевіряється. Виявлення помилки працює завжди. Для виправлення потрібна друга копія.
У пулі з одним диском ZFS повідомляє правду й на цьому зупиняється. zpool status -v показує це так:
status: One or more devices has experienced an error resulting in data
corruption.
action: Restore the file in question if possible. Otherwise restore the
entire pool from backup.
errors: Permanent errors have been detected in the following files:
/tank/data/archive.tarУ повідомленні вказано пошкоджений файл. ext4 повернула б ці байти без жодного повідомлення, тому це вже корисна інформація. ZFS все одно не може виправити помилку, оскільки в пулі немає другої копії, з якої можна відновити дані.
У mirror те саме читання обслуговується з працездатної копії, пошкоджений блок перезаписується, а подія з’являється в стовпці CKSUM у zpool status. Це self-healing, і для нього потрібні два пристрої.
sudo zpool create -o ashift=12 tank mirror /dev/disk/by-id/DISK1 /dev/disk/by-id/DISK2У VPS сховище на хості зазвичай уже має надлишковість, часто це RAID 10 у гіпервізорі. Це захищає від відмови диска. Але така схема не повідомляє, коли блок повернувся пошкодженим, оскільки масив не може визначити, яка копія правильна. ZFS це знає, бо порівнює дані з контрольною сумою, яку записав сам.
Якщо у вас один віртуальний диск і потрібна певна можливість виправлення помилок, sudo zfs set copies=2 tank/important зберігає дві копії кожного блока цього dataset на одному диску. Це вдвічі збільшує обсяг, який використовує dataset, дає змогу пережити пошкодження блока, але не допоможе, якщо весь том стане недоступним.
Scrub читає всі дані в пулі та перевіряє їх.
sudo zpool scrub tank
zpool status tankСправний пул завершує перевірку рядком на кшталт scan: scrub repaired 0B in 00:04:11 with 0 errors. Додайте scrub до розкладу; для невеликого пулу достатньо запускати його щомісяця.
systemctl list-unit-files 'zfs-scrub*'
sudo systemctl enable --now zfs-scrub-monthly@tank.timerНабори даних є одиницею політик
Набір даних — це файлова система всередині pool. Створити його недорого, тому створюйте окремий набір для кожного завдання. Властивості успадковуються від pool вниз по ієрархії. Це дає змогу один раз задати значення за замовчуванням і перевизначити його там, де це потрібно. У FreeBSD jail зазвичай запускають саме так: для кожного jail створюють окремий набір даних. Тоді окремий jail можна самостійно створювати зі snapshot і відновлювати до попереднього стану. Це одна з ознак, що відрізняє jail від контейнера Docker.
sudo zfs create tank/data
sudo zfs create tank/pg
sudo zfs set compression=lz4 tank
sudo zfs set atime=off tank
sudo zfs set quota=20G tank/data
sudo zfs set recordsize=16K tank/pg
zfs get -r compression,compressratio,quota tankСтиснення часто не вмикають з обережності, але це неправильний підхід. lz4 потребує небагато CPU і зменшує обсяг даних, які потрібно записати на диск. Тому для даних, що добре стискаються, читання та запис зазвичай стають швидшими. zstd стискає сильніше, але потребує більше CPU. Це підходить для журналів і архівів, які рідко читають повторно. Перевірте фактичний результат за допомогою zfs get compressratio tank. Пам’ятайте, що коефіцієнт враховує лише дані, записані після встановлення властивості.
recordsize — це найбільший блок, який записує набір даних. Типове значення — 128K. Якщо база даних записує сторінки розміром 8 KiB у записи по 128 KiB, один малий запис перетворюється на читання всього запису, його зміну та повторний запис. Встановіть recordsize=16K для набору даних бази даних до завантаження даних, оскільки властивість застосовується лише до нових блоків.
quota не дає одному набору даних заповнити весь pool. Коли ZFS pool заповнений майже на 100%, він працює повільно, а звільнити місце стає складно. Тому навмисно залишайте запас вільного простору.
Знімки не займають місця, доки дані не змінюються
ZFS ніколи не перезаписує активний блок. Він записує новий блок і оновлює вказівники — саме це означає copy-on-write. Знімок — це запис із вказівкою «зберегти блоки, на які цей dataset посилається зараз», тому його створення відбувається миттєво й не займає додаткового місця.
sudo zfs snapshot tank/data@2026-08-11
zfs list -t snapshot -o name,used,refer -r tank/dataСтовпець USED для знімка показує простір, який утримує лише цей знімок. Спочатку його значення близьке до нуля, а потім зростає, коли ви змінюєте або видаляєте дані, оскільки старі блоки більше не можна звільнити.
Щоб повернути файл, не потрібен окремий етап відновлення.
ls /tank/data/.zfs/snapshot/
cp /tank/data/.zfs/snapshot/2026-08-11/notes.txt /tank/data/notes.txtКаталог .zfs прихований навіть від ls -a, доки ви не виконаєте sudo zfs set snapdir=visible tank/data. Створіть знімок до того, як він знадобиться, оскільки без нього випадковий rm -rf переведе вас до процедури відновлення ext4, яка починається з відмонтування диска, а далі ситуація лише ускладнюється.
Відкат видаляє все, що було записано після створення знімка.
sudo zfs rollback tank/data@2026-08-11Операція не виконується, якщо існують новіші знімки, а -r знищує ці новіші знімки, щоб продовжити. Перед натисканням Enter двічі перевірте назву dataset.
Знімок не є резервною копією. Він зберігається в тому самому pool, на тому самому томі й на тому самому сервері. Відмова тома або один zpool destroy знищує знімки разом із даними. Знімки захищають від власного rm і невдалого оновлення, що охоплює багато реальних інцидентів, але не захищають від подій, які впливають на сам pool. Повний розбір наведено тут: чому знімок VPS не є резервною копією.
Надсилання й отримання: реплікація однією командою
zfs send перетворює snapshot на потік байтів у стандартному виведенні, а zfs receive перетворює цей потік назад на dataset. Перша копія є повним надсиланням.
sudo zfs snapshot tank/data@daily-2026-08-11
sudo zfs send tank/data@daily-2026-08-11 | ssh backup.example.com "sudo zfs recv -F backup/data"Після цього надсилайте лише зміни між двома snapshot.
sudo zfs snapshot tank/data@daily-2026-08-12
sudo zfs send -i tank/data@daily-2026-08-11 tank/data@daily-2026-08-12 | ssh backup.example.com "sudo zfs recv backup/data"На стороні отримувача все одно має зберігатися snapshot, з якого ви надсилаєте дані. Якщо його немає, отримання припиняється з помилкою cannot receive incremental stream: most recent snapshot of backup/data does not match incremental source, оскільки ZFS не має бази для застосування різниці. Надсилайте дані зі snapshot, який є на обох сторонах, або почніть знову з повного надсилання.
Надайте права на цільовій системі замість використання віддаленого root: sudo zfs allow -u backupuser create,mount,receive backup/data.
Це повноцінна резервна копія на віддаленому майданчику за однієї умови. На віддаленому кінці має бути ZFS pool, оскільки object storage не може отримувати потік. Якщо ціллю є S3-compatible storage або звичайний Linux host, використовуйте інструмент, який підтримує відповідний протокол, а резервне копіювання VPS за допомогою restic описує цей варіант.
Чому ZFS використовує так багато RAM? ARC
ARC (adaptive replacement cache) — це кеш читання ZFS. Він зберігається в пам’яті ядра, а не у звичайному кеші сторінок Linux, тому free -h не показує його в категорії buff/cache. Ця пам’ять відображається як використана. Сервер ZFS, на якому пам’ять майже повністю зайнята, зазвичай має прогрітий кеш. Саме це пояснює більшість повідомлень «ZFS з’їв мою RAM».
Ліміт за замовчуванням навмисно встановлено доволі високим. OpenZFS 2.3 встановлює максимальний розмір ARC на більше з двох значень: обсяг RAM мінус 1 GiB або 5/8 обсягу RAM. OpenZFS 2.2 і попередні версії в Linux використовували половину RAM, тоді як FreeBSD уже використовував нове правило. Виконайте zfs version, щоб визначити, яке правило застосовується у вашій системі.
The data behind this chart
[
{
"label": "2 GB VPS",
"openzfs_2_2_linux_gib": 1,
"openzfs_2_3_gib": 1.25
},
{
"label": "4 GB VPS",
"openzfs_2_2_linux_gib": 2,
"openzfs_2_3_gib": 3
},
{
"label": "8 GB VPS",
"openzfs_2_2_linux_gib": 4,
"openzfs_2_3_gib": 7
},
{
"label": "16 GB VPS",
"openzfs_2_2_linux_gib": 8,
"openzfs_2_3_gib": 15
}
]Ці значення — задокументоване правило за замовчуванням, застосоване до поширених розмірів інстансів, а не результати вимірювань на запущеному сервері. Для інстансу з 4 GB правило 2.3 дозволяє ARC розміром 3 GiB. На тому самому сервері з версією 2.2 ARC обмежується значенням 2 GiB. Для інстансу з 2 GB за правилом 2.3 все ще дозволено 1.25 GiB. Застосунку дістанеться те, що залишиться.
Замість таблиці перегляньте фактичні значення на власному сервері:
grep -E '^(size|c_max) ' /proc/spl/kstat/zfs/arcstats
arc_summary | head -n 20У третьому стовпці вказано байти. c_max — поточний максимальний ліміт, а size — обсяг пам’яті, який ARC використовує зараз.
ARC справді повертає пам’ять. Ядро сигналізує про нестачу пам’яті, після чого ARC зменшується. Проблема полягає в часі реакції: зменшення ARC запускається саме цим сигналом, тому процес, якому одночасно потрібно кілька сотень MiB, може зіткнутися з OOM (out of memory) killer, поки ARC ще вивільняє пам’ять. На сервері з 2 GB, де працюють база даних і вебсервер, це не рідкісна ситуація. У посібнику OpenZFS наведено таке саме застереження щодо ручної зміни ліміту: його зменшення «не призведе до зменшення ARC без тиску на пам’ять, який ініціює це зменшення».
Як обмежити ARC на невеликому VPS
Спочатку визначте потреби робочого навантаження в пам’яті. Підсумуйте обсяг пам’яті, потрібний базі даних і застосунку, залиште запас для операційної системи, а решту виділіть ARC. Для інстансу з 4 GB RAM, на якому працюють Postgres і один вебзастосунок, розумним початковим значенням буде від 512 MiB до 1 GiB ARC.
Застосуйте значення без перезавантаження системи. Значення задається в байтах. У цьому прикладі це 1 GiB.
echo 1073741824 | sudo tee /sys/module/zfs/parameters/zfs_arc_maxЗробіть це налаштування постійним після перезавантаження.
echo 'options zfs zfs_arc_max=1073741824' | sudo tee /etc/modprobe.d/zfs.conf
sudo update-initramfs -uКрок із initramfs важливий, оскільки модуль може завантажитися з initramfs до монтування кореневої файлової системи. У такому разі він не прочитає щойно створений файл. Після перезавантаження перевірте значення за допомогою рядка c_max з arcstats.
З документації випливають два обмеження. Не можна встановити це значення назад у 0 під час роботи системи. Щоб скасувати обмеження, відредагуйте файл і перезавантажте систему. Зменшення значення також не зменшує великий ARC одразу.
У FreeBSD таке саме обмеження задається через sysctl у vfs.zfs.arc. Виконайте sysctl vfs.zfs.arc, щоб переглянути поточні значення та точну назву параметра у вашій версії. Потім запишіть максимальне значення в /boot/loader.conf.
Для невеликого сервера важливі ще два правила роботи з пам’яттю. Не вмикайте дедуплікацію, оскільки таблиця дедуплікації зберігається в пам’яті. Поширене орієнтовне правило — від 1 до 3 GB RAM на 1 TB унікальних даних. Не розміщуйте swap на zvol — блоковому пристрої, створеному з пулу, — оскільки обмін через файлову систему, яка намагається звільнити пам’ять, може призвести до deadlock системи. Розміщуйте swap на звичайному розділі або у swap file за межами пулу.
Коли ext4 або XFS разом із restic є кращим вибором
ZFS виправдовує себе на сервері з вільною оперативною пам’яттю та другим томом. В інших випадках краще використовувати звичайну файлову систему та повноцінний інструмент резервного копіювання. Обирайте ext4 або XFS, якщо:
- Інстанс має 2 GB або 4 GB RAM, і робоче навантаження потребує всієї цієї пам’яті.
- Є один віртуальний диск і немає другої копії, тому ZFS забезпечує виявлення пошкоджень без можливості їх виправити.
- Резервні копії зберігаються в object storage або на звичайному Linux-хості, тому жодна з цих систем не може приймати потік
zfs send. - Ви використовуєте Debian із DKMS і не можете дозволити собі оновлення ядра, після якого модуль залишиться незбірним.
- Вам потрібен ZFS на root-файловій системі, а образи провайдера пропонують лише ext4.
Залишайте ZFS, якщо маєте окремий том даних, достатньо RAM (від 8 GB працювати комфортно) та план, у якому snapshots і zfs send використовуються на практиці, а не просто увімкнені. В усіх інших випадках ext4 із restic, який записує зашифровані дедупліковані резервні копії до сховища, яким сервер не керує, забезпечує майже той самий результат без витрат оперативної пам’яті.
Режими відмови та повідомлення, які ви побачите
Пул зникає після перезавантаження. zpool status виводить no pools available. Сервіс імпорту читає /etc/zfs/zpool.cache, тому пул, якого немає в цьому файлі, не імпортується під час завантаження. sudo zpool import показує, які пули можна імпортувати, sudo zpool import tank імпортує пул, а sudo zpool set cachefile=/etc/zfs/zpool.cache tank зберігає цю конфігурацію. Для пулу, який не було коректно експортовано з іншої системи, з’являється повідомлення cannot import 'tank': pool may be in use from other system. sudo zpool import -f tank обходить цю перевірку, але використовуйте його лише після того, як переконаєтеся, що цей пул не використовується іншим хостом.
modprobe: FATAL: Module zfs not found in directory /lib/modules/6.12.0-... у Debian після оновлення ядра. DKMS не зібрав модуль для нового ядра, зазвичай тому, що не встановлено відповідні headers. dkms status показує, для яких ядер зібрано модулі. Потім sudo apt install -y linux-headers-$(uname -r) sudo dkms autoinstall повторно збирає модуль, а sudo zpool import tank імпортує пул.
Пул заповнений, але файли видалено. Видалені дані залишаються на диску, доки на них посилається snapshot, тому du і df показують різні значення. zfs list -o space -r tank розділяє використання на USEDDS і USEDSNAP. Велике значення USEDSNAP вказує на причину. Знищіть старі snapshots за допомогою sudo zfs destroy tank/data@2026-06-01, після чого місце звільниться.
Лічильники CKSUM у zpool status зростають. Компонент нижче рівня ZFS повертає пошкоджені дані. У mirror це попередження, а блок було відновлено. У пулі з одним диском файл втрачено, zpool status -v називає цей файл, а відновити його можна з резервної копії, яка не зберігається в цьому пулі.
Сервер працює повільно та використовує swap. Обмежте ARC, як описано вище, потім виконайте arc_summary і перевірте коефіцієнт влучань. Якщо ARC замалий для робочого набору даних, кожне читання звертається до диска. У такій ситуації звичайна файлова система, що використовує page cache, працювала б краще.
FAQ
Скільки RAM потрібно ZFS на VPS?
ZFS працює на інстансі з 2 GB RAM. Справжнє питання полягає в тому, скільки RAM залишиться для застосунку. Без додаткового налаштування OpenZFS 2.3 збільшує ARC до більшого з двох значень: RAM мінус 1 GiB або 5/8 RAM. Тому сервер із 4 GB RAM може передати кешу 3 GiB. Установіть zfs_arc_max у значення, яке може виділити ваше робоче навантаження, а потім перевірте його за рядком c_max у /proc/spl/kstat/zfs/arcstats.
Чи є знімок ZFS резервною копією?
Ні. Знімок зберігається в тому самому pool, що й дані. Він переживе пошкоджений rm і невдале оновлення, але буде втрачений разом із pool або інстансом. Перетворіть його на резервну копію, надіславши на іншу машину за допомогою zfs send, або використайте інструмент резервного копіювання, який записує дані в сховище, що не контролюється цим сервером.
Чи однаково працює ZFS у FreeBSD і Linux?
Починаючи з OpenZFS 2.0 у December 2020, використовується та сама кодова база, ті самі команди й той самий формат даних на диску, а pool можна переносити між цими системами. Відмінність полягає в пакуванні. FreeBSD постачає ZFS у складі базової системи. У Linux рішення залежить від дистрибутива: Ubuntu вбудовує модуль у свої kernel packages, а Debian збирає його на вашій машині за допомогою DKMS. Тому після оновлення kernel можна залишитися без модуля, доки його повторне збирання не завершиться успішно.
Чи може ZFS виправити пошкодження на VPS з одним диском?
ZFS виявляє пошкодження та вказує файл, але не може його виправити, оскільки для виправлення потрібна друга копія блоку. zfs set copies=2 для dataset створює таку другу копію за подвійного використання простору. Це дає змогу обробити пошкоджений блок, але не втрачений volume. Mirror між двома volumes — це рішення, яке справді усуває пошкодження.
Чи сповільнює compression роботу сервера?
lz4 зазвичай пришвидшує роботу. Стиснуті блоки означають менший обсяг записуваних і зчитуваних даних, а витрати CPU на блок невеликі порівняно з обсягом роботи диска, якого вдається уникнути. Установіть compression=lz4 у корені pool, щоб кожен dataset успадковував це налаштування, а потім перевірте zfs get compressratio tank після запису реальних даних.