Стиснення ZFS за допомогою zstd: вибір рівнів без перевантаження CPU

Було корисно?

Стиснення в ZFS — це один із тих рідкісних руків, що можуть зробити сховище швидшим, дешевшим і тихішим — одночасно. Воно також може перетворити цілком здорову систему на «обігрівач», прив’язаний до CPU, якщо ставитись до «zstd-19» як до рис характеру. Важливо підходити до вибору рівнів як SRE: базуючись на вимірах, формі навантаження та режимах відмов, а не на відчуттях.

Це польовий посібник для роботи з стисненням zstd у продакшені на ZFS: як поводяться різні рівні, як виглядає «добре», що перевіряти при погіршенні, і як налаштовувати без ненавмисного створення ферми для бенчмарків. Ми залишимось практичними: команди, які можна виконати сьогодні, як їх інтерпретувати і які рішення з цього випливають.

Чому стиснення — це функція продуктивності

Стиснення в ZFS відбувається inline. Це означає, що при записах ZFS стискає блоки до того, як вони потраплять на диск; при читаннях він розпаковує блоки після зчитування з диска і перед тим, як вони потраплять до буферів вашого застосунку. Багато хто класифікує стиснення як «економію дискового простору», але на практиці це часто інструмент продуктивності.

Менше байтів на рух часто швидше, ніж менше витрачених CPU-циклів

Системи зберігання зазвичай обмежені одним із трьох: латентністю, пропускною здатністю або CPU. Стиснення обмінює CPU на менше байтів по каналу і на диску. Якщо ваше навантаження I/O-bound (поширено), то цей обмін — виграш.

Ось ментальна модель, яка допоможе не обманювати себе:

  • Якщо вузьке місце — сховище, стиснення може збільшити ефективну пропускну здатність і зменшити read amplification.
  • Якщо вузьке місце — CPU, агресивне стиснення може похитнути продуктивність і спричинити каскадні тайм-аути.
  • Якщо навантаження чутливе до латентності, вам важливі p99 і хвостові сплески, а не середня пропускна здатність.

Стиснення також тихо зменшує фрагментацію долі: менше записаних блоків означає менше алокацій, рідше оновлюються metaslab і іноді менший тиск на фрагментацію з часом. Це не магія і не гарантія, але цього достатньо, щоб проявитися у довгоживучих пулах.

Жарт перед тим, як перейти до серйозного: стиснення схоже на дієту — усім подобаються «до/після», але ніхто не любить рахувати CPU-калорії.

Як zstd поводиться в ZFS (і що насправді означають рівні)

Zstandard (zstd) розроблений так, щоб бути швидким на низьких рівнях і вміти давати сильне стиснення на вищих. У ZFS зазвичай задають стиснення на рівні dataset через compression=zstd або compression=zstd-N. Рівень визначає, наскільки сильно ZFS намагається знайти стисненні шаблони.

Що ZFS стискає: блоки розміру recordsize (зазвичай)

ZFS стискає окремі блоки, зазвичай до розміру dataset-ного recordsize (для файлових систем) або volblocksize (для zvol). Це головна причина, чому «рівень стиснення» не дає універсальної відповіді: стиснення 128K блоків для файлового сервера — інша гра, ніж стиснення 16K блоків для бази даних, і зовсім інша ніж 8K блоків для zvol, що підкріплює VM-диск.

Рівні не лінійні — і «кращий коефіцієнт» може бути гіршим

Рівні zstd збільшують витрати CPU швидше, ніж покращують коефіцієнт стиснення. Крива крута: низькі рівні часто «майже безкоштовні», тоді як високі рівні можуть бути драматично дорожчими за скромний додатковий виграш. На сучасних CPU розпакування зазвичай значно дешевше за стискання, що важливо для навантажень, де більше читань.

Також: кращий коефіцієнт стиснення не завжди краще для ZFS. Коли блоки стають меншими, ви зменшуєте I/O, але можете збільшити витрати CPU, погіршити ефективність prefetch або змінити поведінку ARC і L2ARC. Правильний рівень — той, що робить ваше навантаження швидшим або дешевшим без перенесення вузького місця в гірший стан.

zstd у ZFS не «підходить усім»

Реальні робочі навантаження мають характер:

  • VM-образи: багато випадкових операцій чит/запис, змішана стискуваність, зазвичай вигідні помірному стисненню, але можуть швидко виявити витрати CPU.
  • Бази даних: структуровані дані, журнали та індекси різняться; іноді виграш великий, іноді майже ніякого. Важливі хвостові затримки.
  • Резервні копії: зазвичай послідовні, дуже стискувані (особливо текст, JSON, CSV) і терпимі до витрат CPU — поки відновлення не стає бізнес-подією.
  • Медіа: вже стискані; стиснення часто марнує CPU, хоча метадані й допоміжні файли можуть виграти.

Факти та історичний контекст для зустрічей

Це конкретні пункти, які допомагають, коли хтось запитує: «Чому ми знову змінюємо стиснення?»

  1. Стиснення в ZFS існує давно — це не модний додаток. Раніше в ZFS часто використовували LZJB, потім lz4 став практичним дефолтом у багатьох впровадженнях через достатню швидкість, щоб бути «завжди ввімкненим».
  2. zstd створив Yann Collet (той самий інженер, що стоїть за LZ4), спроектований як спектр: швидкість, схожа на lz4 на низьких рівнях, і сильні коефіцієнти на вищих.
  3. Inline стиснення змінює фізичний layout: дані зберігаються стиснутими на диску. Ви не «заощаджуєте простір пізніше» — ви змінюєте, скільки секторів потрапляє на носій прямо зараз.
  4. Сучасні CPU можуть дуже швидко розпаковувати відносно магнітних дисків і навіть багатьох SSD; розпакування часто не є обмежувачем — стискання є.
  5. ZFS звітує стиснення по блоках і по dataset, але compressratio — не бенчмарк; він включає нюанси як метадані, вирівнювання і те, як блоки перезаписувалися з часом.
  6. Стиснення взаємодіє з recordsize: більші блоки можуть краще стискатись, але дорожчі при перезаписі і можуть збільшити write amplification для дрібних випадкових записів.
  7. Dedup — не те саме, що стиснення, і історично створював більше аварій, ніж зекономлених бюджетів при випадковому увімкненні; стиснення — безпечніша важільна опція.
  8. ZFS «копіює» і робить контрольні суми для всього (copy-on-write + end-to-end checksumming). Стиснення має вкладатися в цей pipeline, тому наклад CPU може проявитися як хвостова латентність під навантаженням.

Вибір рівнів zstd за робочим навантаженням (без підпалювання CPU)

Стандартна позиція: почніть консервативно, потім підвищуйте з доказами

Якщо хочете однозначну базову рекомендацію: використовуйте zstd на низькому рівні для більшості dataset-ів, а потім вибірково підвищуйте там, де є докази користі. У багатьох продакшн-середовищах це означає compression=zstd (що відповідає дефолтному рівню) або явний низький рівень як zstd-1 до zstd-3 для загального призначення файлових систем.

Чому? Тому що зазвичай можна отримати значне зменшення записаних і зчитаних байтів з мінімальним впливом на CPU. Це зменшення також покращує ефективність кешів: ARC і page cache фактично «стають більшими», коли та сама RAM вміщує більше логічних даних.

Рекомендації за типом навантаження (практичні, не догматичні)

Файлові системи загального призначення (домашні директорії, артефакти збірки, логи)

Почніть з zstd-1 до zstd-3. Ці рівні зазвичай дають «легкі виграші» (текст, JSON, бінарні файли з заповненими нульовими ділянками) без перетворення стиснення на CPU-завдання.

Логи особливо цікаві: вони дуже добре стискаються, а сплески логів можуть бути інтенсивними. Низький рівень zstd зазвичай справляється; вищі рівні можуть стати помітними в p99 latency при бурстах — саме тоді, коли вам менше всього потрібна додаткова латентність.

Зберігання VM (zvols або файлові системи з qcow2/raw)

Спочатку використовуйте zstd-1 або zstd-2. I/O VM часто випадковий і чутливий до латентності. Стиснення може допомогти через велику кількість нулів і повторюваних шаблонів у образах, але патерн записів швидко проявить наклад CPU.

Якщо hypervisor-хост вже завантажений CPU (overcommit, шифрування, мережеві накладні), тримайте стиснення «дешевим». Якщо сховище — вузьке місце і на хостах є запас CPU, ретельно протестуйте zstd-3 або zstd-4.

Бази даних

Будьте консервативними й вимірюйте p99. DB-навантаження зазвичай мішані: WAL/redo журнали (часто стискувані), data файли (можливо), індекси (залежно). Вартість додаткового CPU у шляху зберігання може проявитися як хвостова латентність, що призведе до скарг «чому додаток повільний?»

Почніть з zstd-1 або zstd-2 для даних, можливо вищий для архівних tablespaces, якщо конфігурація БД дозволяє розділення.

Репозиторії бекапів

Тут ви можете обґрунтувати вищі рівні — іноді. Якщо робота з бекапами послідовна і репозиторій запису суворо вікном часу, zstd-3 до zstd-6 може мати сенс, якщо є запас CPU і сховище дороге або повільне. Але пам’ятайте відновлення: розпакування зазвичай дешеве, та процес відновлення може навантажувати CPU з інших причин (чексуми, мережа, шифрування).

Якщо ваше backup-пЗ вже виконує стиснення (або дедуплікацію і стиснення), стиснення на ZFS може давати мало додаткового. Вимірюйте перед тим, як святкувати.

Вже стиснені медіафайли (JPEG, MP4, ZIP)

Використовуйте низький рівень або не вмикайте — але «не вмикайте» не обов’язково. ZFS спробує стиснути кожен блок і може вирішити, що це недоцільно; але сама спроба коштує CPU. На системах з обмеженим CPU, що віддають медіа, встановіть низьке стиснення. На загальних пулах залишати низьке стиснення часто нормально, бо fast-path «не стискується» досить ефективний.

«Паління» CPU зазвичай пов’язане з конкуренцією, а не одним потоком

У продакшені стиснення рідко вбиває через один довгий блок. Воно вбиває через тисячі блоків, що стискаються одночасно, і раптом ваші storage-ноди починають виглядати як сервера пакетної обробки. ZFS охоче використовуватиме CPU, щоб встигати за I/O, і якщо ви працюєте на краю (часто так), ресурс вичерпуватиметься.

Другий жарт і підсумок: найкращий рівень стиснення — той, що не перетворює ваш пристрій зберігання на розподілену тестову систему на CPU.

Три корпоративні міні-історії

1) Інцидент через хибне припущення: «Стиснення впливає тільки на дисковий простір»

Компанія, з якою я працював, тримала внутрішній репозиторій артефактів на ZFS. Це був класичний випадок «працює поки не перестане»: деви багато пушать у робочий час, CI галасливий, і пул сховище був розрахований за ємністю з «достатнім» CPU, бо на папері машина виглядала потужною.

Хтось змінив головний dataset з compression=lz4 на compression=zstd-15 після огляду ємності. Припущення було простим і дуже людським: «стискання — це справа зберігання». Зміна вийшла у тихий період, початкові тести були нормальні, і compressratio покращився настільки, що всім стало приємно.

Два дні потому відбувся великий реліз гілки продукту. CI став шаленіти: tarball-и, контейнери, логи та купа дрібних файлів. Сховище не вичерпало простір — воно вичерпало час. Латентність записів підскочила, потоки застосунків накопичилися, і сервіс артефактів почав повертати тайм-аути. Інженери звинувачували мережу, потім DNS (обряд ініціації), і лише пізніше помітили, що storage-ноди зайняті CPU з ростом system time.

Рішення було нескладним: повернути низький рівень zstd, перезапустити заторені сервіси, щоб очистити беклог, і ввести процес змін для властивостей сховища. Урок закарбувався, бо коштував дорого у плані часу інженерів і дня з питаннями «чому все так повільно?»

Постмортем-висновок, що мав значення: стиснення — це частина I/O-пайплайну. Ставтесь до нього так само, як до шифрування чи зміни recordsize — вимірюйте, впроваджуйте поетапно і спостерігайте хвостові латентності.

2) Оптимізація, що відігралася назад: «Погаймо ті рівні для кращого коефіцієнта»

В іншому середовищі команда обслуговувала платформу VM на ZFS. Вартість зберігання була під прицілом, тож інженер запропонував підняти рівні стиснення по всій інфраструктурі. Ідея добре виглядала в таблиці: менше терабайтів, менше дисків, менше майбутніх покупок. На папері були запаси CPU — поки їх не не стало.

Назад відбилося через взаємодію, яку ніхто не замоделював: найзавантаженіші хости також виконували шифрування at rest і багато snapshot churn. Стиснення, шифрування, checksumming, метадані snapshot — кожне окремо «нормально», але разом вони утворили пайплайн, що почав підсилювати латентність під навантаженням. Перший симптом навіть не був у storage-оповіщеннях; це був drift часу в гостах VM і час від часу файлові помилки, коли гості зазнавали довгих I/O стопів.

Вони намагалися виправити це, як часто роблять доброчесні інженери: підкласти ще налаштувань. Збільшили ARC, підкоригували prefetch і змінили глибину черг. Це трохи допомогло, але основна проблема була в CPU-навантаженні в стеку зберігання під пікованими записами. Вищі рівні стиснення були множником.

Зрештою вирішення було майже нудним: повернути більшість dataset-ів до низького zstd, залишити вищі рівні тільки для холодних, стискуваних томів, і додати дашборд, що корелює latency (p95/p99), CPU і IOPS з налаштуваннями стиснення. Збереження ємності зменшилися — але платформа перестала генерувати дивні «VM проклята» тікети.

У ретро найкращою фразою було: «Ми оптимізували за числом, яким можна хвалитись, а не за тим, що відчувають користувачі». Це хороше правило для життя, не лише для ZFS.

3) Нудна але правильна практика, що врятувала день: «Політики на рівні dataset + канарки»

Більш зріла організація ставилася до властивостей ZFS як до конфігурації застосунку: версіонована, переглянута і впроваджена поетапно. Не тому що вони любили процес, а тому що їх вже палили раніше. У них була чітка політика: загальні dataset-и отримують низький zstd; спеціальні dataset-и (бекапи, архіви) можуть використовувати вищі рівні, якщо проходять бенчмарки; dataset-и баз даних повинні показати відсутність регресії p99.

Вони також використовували канарки: один storage-нод і невелика частина навантажень отримували зміну першими. Суть була не в ідеальності, а в видимості. Вони дивилися кілька сигналів: percentiles латентності записів, використання CPU (user/system) і тайм-аути на рівні застосунку. Якщо щось змінювалося в погану сторону, rollback був негайним і бездискусійним, бо це було очікувано.

Під час апгрейду обладнання вони перейшли з старшого покоління CPU на новіше і використали можливість переглянути стиснення. Оскільки у них були базові метрики, вони змогли довести, що zstd-3 безпечний для набору навантажень, які раніше вимагали zstd-1. Це дало реальну ємність і підвищення пропускної здатності без драм.

День, коли це «врятувало день», став несподіваним: нова команда почала зберігати великі обсяги напівструктурованих логів. На менш дисциплінованій платформі це спричинило б або аварію з ємністю, або інцидент продуктивності. Тут dataset вже мав правильний recordsize і рівень стиснення, і платформа поглинула ріст як ні в чому не бувало — в певному сенсі, вона цього й чекала.

Практичні задачі: команди + інтерпретація (12+)

Все нижче має виконуватись на типовій Linux-системі з доступними утилітами ZFS. Вивід залежить від дистрибутиву та версії ZFS; важливі шаблони інтерпретації.

Задача 1: Побачити поточні налаштування стиснення по dataset-ах

cr0x@server:~$ zfs get -r -o name,property,value,source compression tank
NAME                PROPERTY     VALUE     SOURCE
tank                compression  zstd      local
tank/vm             compression  zstd-2    local
tank/db             compression  zstd-1    local
tank/backups        compression  zstd-6    local
tank/media          compression  off       local

Інтерпретація: Це показує, що встановлено і звідки (local vs inherited). Якщо ви бачите несподівано високий рівень, що успадкований від батька, саме так «маленька зміна» може стати «аварією на всю платформу».

Задача 2: Перевірити фактичні результати стиснення (не гадати)

cr0x@server:~$ zfs get -o name,used,logicalused,compressratio -r tank
NAME         USED  LOGICALUSED  RATIO
tank         4.20T 6.10T        1.45x
tank/vm      1.80T 2.10T        1.17x
tank/db      900G  1.05T        1.19x
tank/backups 1.10T 2.70T        2.45x
tank/media   400G  410G         1.02x

Інтерпретація: logicalused vs used дає реалістичну картину. Бекапи добре стискаються; медіа — ні. Якщо compressratio близький до 1.0x, високий рівень zstd — це насамперед демонстрація CPU.

Задача 3: Знайти dataset-и, що марнують CPU (високий рівень, низький коефіцієнт)

cr0x@server:~$ zfs get -H -o name,value compression,compressratio -r tank | paste - - | head
tank	zstd	tank	1.45x
tank/vm	zstd-2	tank/vm	1.17x
tank/db	zstd-1	tank/db	1.19x
tank/backups	zstd-6	tank/backups	2.45x
tank/media	off	tank/media	1.02x

Інтерпретація: Цей швидкий і простий вигляд допомагає виявити «zstd-12 з 1.05x». Якщо знайдете таке, швидше за все знайшли вільний CPU.

Задача 4: Безпечно змінити стиснення (і розуміти, що це робить)

cr0x@server:~$ sudo zfs set compression=zstd-2 tank/db
cr0x@server:~$ zfs get compression tank/db
NAME     PROPERTY     VALUE   SOURCE
tank/db  compression  zstd-2  local

Інтерпретація: Це впливає на нові записані блоки. Існуючі дані залишаються зі старим стисненням до їхнього перезапису (через нормальний churn або свідомий перезапис).

Задача 5: Швидко виміряти I/O латентність і пропускну здатність за допомогою iostat

cr0x@server:~$ iostat -x 1 5
Linux 6.6.0 (server) 	12/24/2025 	_x86_64_	(32 CPU)

avg-cpu:  %user   %nice %system %iowait  %steal   %idle
          22.10    0.00    8.50    1.20    0.00   68.20

Device            r/s     w/s   rkB/s   wkB/s  r_await  w_await aqu-sz  %util
nvme0n1         120.0   900.0  6400.0 51200.0    0.45    2.10   1.20   82.0

Інтерпретація: Якщо %util високий і awaits ростуть, ви storage-bound. Якщо awaits в нормі, але застосунок повільний, можливо ви CPU-bound (стиснення або checksumming) або проблема в іншому місці.

Задача 6: Спостерігати I/O та латентність на рівні pool

cr0x@server:~$ zpool iostat -v 1 5
                              capacity     operations     bandwidth
pool                        alloc   free   read  write   read  write
--------------------------  -----  -----  -----  -----  -----  -----
tank                        4.20T  1.80T    800   1200   90M   140M
  mirror                    4.20T  1.80T    800   1200   90M   140M
    nvme0n1                    -      -    400    600   45M    70M
    nvme1n1                    -      -    400    600   45M    70M
--------------------------  -----  -----  -----  -----  -----  -----

Інтерпретація: Пропускна здатність і операції показують, чи ви штовхаєте багато дрібних I/O або менше великих. Стиснення зазвичай важливіше, коли ви bandwidth-bound; воно може шкодити більше, коли ви IOPS- і latency-bound і CPU обмежений.

Задача 7: Перевірити тиск ARC і стан пам’яті

cr0x@server:~$ arcstat 1 5
    time  read  miss  miss%  dmis  dm%  pmis  pm%  mmis  mm%  arcsz     c
12:00:01   900   120     13    40   4     60   7     20   2   48.0G  64.0G
12:00:02   880   140     15    55   6     65   7     20   2   48.1G  64.0G

Інтерпретація: Стиснення змінює ефективну щільність кеша. Якщо ваш miss rate високий, навіть помірний коефіцієнт стиснення може зменшити фізичні зчитування, бо більше логічного вмісту вміщується в ARC.

Задача 8: Перевірити per-dataset recordsize і чому це впливає на стиснення

cr0x@server:~$ zfs get -o name,property,value recordsize tank/vm tank/db tank/backups
NAME         PROPERTY    VALUE
tank/vm      recordsize  128K
tank/db      recordsize  16K
tank/backups recordsize  1M

Інтерпретація: Більший recordsize може покращити коефіцієнт стиснення для послідовних навантажень (як-от бекапи), але може збільшити write amplification для дрібних випадкових записів (як бази даних). Не «стандартизовуйте» цю властивість, якщо ви не любите уникальних інцидентів.

Задача 9: Підтвердити, що фактично стискується (швидка вибірка)

cr0x@server:~$ zfs get -o name,compression,compressratio -r tank | egrep 'tank/(vm|db|backups|media)'
tank/vm      zstd-2  1.17x
tank/db      zstd-1  1.19x
tank/backups zstd-6  2.45x
tank/media   off     1.02x

Інтерпретація: Dataset, що постійно залишається близько 1.0x, розповідає історію: або дані нестискувані, або розмір блоків/форма навантаження заважають вигодам. Підвищення рівня zstd рідко це виправить.

Задача 10: Примусово перезаписати (обережно), щоб застосувати нове стиснення

cr0x@server:~$ sudo zfs snapshot tank/backups@pre-recompress
cr0x@server:~$ sudo rsync -a --inplace --info=progress2 /tank/backups/ /tank/backups/
cr0x@server:~$ zfs get -o name,used,logicalused,compressratio tank/backups
NAME         USED  LOGICALUSED  RATIO
tank/backups 1.05T 2.70T        2.57x

Інтерпретація: Перезапис даних може застосувати нове стиснення, але також генерує I/O, ризик фрагментації і багато churn. Зробіть snapshot перш ніж, заплануйте роботу і спостерігайте за станом пула. (І так, rsync на себе — грубий інструмент; використовуйте його обачно.)

Задача 11: Спостерігати сатурацію CPU під навантаженням

cr0x@server:~$ mpstat -P ALL 1 3
Linux 6.6.0 (server) 	12/24/2025 	_x86_64_	(32 CPU)

12:05:01 PM  CPU   %usr %sys %iowait %irq %soft %idle
12:05:02 PM  all   72.0 18.0    0.5   0.0   0.5   9.0
12:05:02 PM   10   95.0  4.0    0.0   0.0   0.0   1.0

Інтерпретація: Якщо CPU завантажені, а iowait низький, система не «чекає диск» — вона виконує роботу. Стиснення, checksumming, шифрування та ядрові накладні — типові підозрювані.

Задача 12: Перевірити стан пула і лічильники помилок перед тим, як звинувачувати стиснення

cr0x@server:~$ zpool status -v tank
  pool: tank
 state: ONLINE
  scan: scrub repaired 0B in 02:14:33 with 0 errors on Sun Dec 21 03:00:00 2025
config:

	NAME        STATE     READ WRITE CKSUM
	tank        ONLINE       0     0     0
	  mirror    ONLINE       0     0     0
	    nvme0n1  ONLINE       0     0     0
	    nvme1n1  ONLINE       0     0     0

errors: No known data errors

Інтерпретація: Налаштування стиснення не виправить диск з помилками або пул, що постійно ресилвериться. Завжди перевіряйте базове здоров’я.

Задача 13: Перевірити властивості dataset-а, що часто супроводжують рішення про стиснення

cr0x@server:~$ zfs get -o name,property,value atime,sync,logbias,primarycache,secondarycache -r tank/vm | head -n 12
NAME     PROPERTY        VALUE
tank/vm  atime           off
tank/vm  sync            standard
tank/vm  logbias         latency
tank/vm  primarycache    all
tank/vm  secondarycache  all

Інтерпретація: Люди часто змінюють стиснення разом з іншими налаштуваннями і потім не можуть атрибутувати причину. Зафіксуйте ці властивості перед експериментом, щоб мати змогу чисто відкатитися.

Задача 14: Підтвердити, що під час реплікації надсилається (стискання має значення)

cr0x@server:~$ sudo zfs send -nPv tank/db@hourly-001 | head
send from @ to tank/db@hourly-001 estimated size is 12.3G
total estimated size is 12.3G

Інтерпретація: Розмір реплікації впливається зміненими блоками і їхнім стисненим розміром на диску. Якщо ви налаштували стиснення і перезаписали дані, трафік реплікації може змінитися істотно — іноді на краще, іноді як несподіваний рахунок за трафік.

Швидкий playbook діагностики

Це порядок дій для ситуації «зараз повільно». Мета — знайти вузьке місце за хвилини, а не виграти диспут про ідеологію стиснення.

Перший крок: вирішіть, чи ви storage-bound або CPU-bound

  1. Перевірте насичення CPU: якщо CPU завантажені і iowait низький, підозрюйте стиснення/checksum/шифрування.
  2. Перевірте awaits та завантаження пристроїв: якщо awaits ростуть і пристрої «гарячі», ви storage-bound (або черги надто глибокі).
  3. Перевірте симптоми застосунку: тайм-аути під час сплесків часто корелюють з p99 I/O latency spike-ами.
cr0x@server:~$ mpstat 1 3
cr0x@server:~$ iostat -x 1 3
cr0x@server:~$ zpool iostat 1 3

Другий крок: ідентифікуйте, які dataset-и залучені

Не налаштовуйте весь пул тільки тому, що один dataset поводиться неправильно.

cr0x@server:~$ zfs list -o name,used,logicalused,compressratio,mountpoint -r tank | head -n 20

Що шукати: найактивніші dataset-и, ті з низькими коефіцієнтами але високими рівнями стиснення, і будь-які dataset-и, що зберігають чутливі до латентності навантаження.

Третій крок: корелюйте рівень стиснення з формою навантаження

Запитайте: багато випадкових записів? послідовні? вже стиснені? багато дрібних файлів? zvol під VM? DB з recordsize 16K? Потім перевірте фактичні властивості.

cr0x@server:~$ zfs get -o name,compression,recordsize,volblocksize,sync -r tank/vm tank/db tank/backups

Четвертий крок: зробіть найменшу безпечну зміну

Якщо підозрюєте наклад CPU на стиснення:

  • Спочатку зменшіть рівень стиснення на ураженому dataset-і.
  • Не перезаписуйте все під час інциденту.
  • Дайте новим записам використовувати нове налаштування і переоцініть.
cr0x@server:~$ sudo zfs set compression=zstd-1 tank/vm
cr0x@server:~$ zfs get compression tank/vm

П’ятий крок: підтвердьте покращення тими ж метриками, якими вимірювали проблему

cr0x@server:~$ iostat -x 1 5
cr0x@server:~$ zpool iostat 1 5

Інтерпретація: Покращення має відобразитися як зменшена латентність записів, менша насиченість CPU, менше тайм-аутів. Якщо ні — стиснення не було вузьким місцем, рухайтесь далі.

Контрольні списки / покроковий план

Розумний план випуску для зміни рівнів zstd

  1. Зробіть інвентар: зафіксуйте стиснення, recordsize/volblocksize, sync налаштування та поточні коефіцієнти.
  2. Виберіть кандидатні dataset-и: обирайте ті з високою I/O-вартістю або значною вартістю ємності, а не все підряд.
  3. Визначте метрики успіху: оберіть p95/p99 latency, використання CPU, пропускну здатність та кількість помилок.
  4. Спочатку канарка: один dataset, один нод або один орендар.
  5. Змінюйте одну змінну: не змішуйте зміни рівня стиснення з recordsize в одному релізі.
  6. Спостерігайте протягом повного робочого циклу: як мінімум один піковий період.
  7. Впроваджуйте або відкатуйте: за результатами вимірів, а не лише за compressratio.

Покроковий метод вибору рівня для нового dataset

  1. Класифікуйте навантаження: VM, DB, backup, logs, media, mixed.
  2. Встановіть recordsize відповідно (не за замовчуванням).
  3. Почніть з низького: compression=zstd-1 або zstd-2.
  4. Виміряйте стискуваність після появи реальних даних (не синтетичних).
  5. Якщо коефіцієнт хороший і є запас CPU, протестуйте один рівень вгору.
  6. Зупиніться, коли маргінальний виграш згладжується або коли починають рухатися хвостові латентності.

Поширені помилки (симптоми та виправлення)

Помилка 1: Встановити високий рівень zstd глобально «бо диски дорогі»

Симптоми: раптова насиченість CPU на storage-нoдах, зростання p99 write latency, тайм-аути застосунків під час сплесків і багато звинувачень на адресу «мережі».

Виправлення: спочатку знизьте рівень на «гарячих» dataset-ах (VM, DB). Залишайте вищі рівні лише для холодних/послідовних dataset-ів, які довели користь. Підтверджуйте за p99 і метриками CPU.

Помилка 2: Оцінювати успіх лише по compressratio

Симптоми: «Ми зекономили 20% простору»), а потім «чому розгортання повільніші?» або «чому наші VM гальмують?»

Виправлення: відстежуйте результати навантаження: percentiles латентності I/O, пропускну здатність під піком і запас CPU. Заощадження простору реальні, але не єдиний KPI.

Помилка 3: Забути, що зміна стиснення не перезаписує старі блоки

Симптоми: змінили рівень стиснення і нічого не змінилося; коефіцієнти не рухаються; команди роблять висновок «zstd не працює».

Виправлення: розумійте, що лише нові записи використовують нове налаштування. Якщо потрібно перезаписати історичні дані — плануйте контрольований rewrite (і очікуйте додаткового I/O і впливу на snapshots).

Помилка 4: Використання «одного recordsize під усіх»

Симптоми: бази даних сповільнюються після встановлення 1M recordsize «для кращого стиснення», або латентність VM зростає після зміни recordsize для dataset-а з образами.

Виправлення: встановлюйте recordsize під навантаження. Compression і recordsize пов’язані; налаштовуйте їх у парі, але змінюйте по одному параметру одночасно.

Помилка 5: Звинувачення стиснення у випадку, коли пул падає

Симптоми: погіршення продуктивності збігається зі зростанням read/write/checksum помилок, scrub-ів що затягуються або серед робіт відбувається resilver.

Виправлення: перевірте zpool status і SMART/NVMe передусім. Пул під відновленням буде повільним незалежно від стиснення.

Помилка 6: Ігнорування взаємодії з шифруванням і sync-записами

Симптоми: стрибки CPU і хвостові латентності після увімкнення шифрування і підвищення рівня zstd; синхронні навантаження погіршуються.

Виправлення: розглядайте рівень стиснення як частину пайплайну. Якщо шифрування увімкнено, будьте консервативніші зі стисненням для «гарячих» dataset-ів. Перевіряйте синхронні навантаження окремо.

FAQ

1) Чи варто вмикати zstd скрізь?

Вмикайте широко на низькому рівні, якщо у вас є запас CPU і ви хочете простішої операційності. Але «всім і на високому рівні» — це шлях до CPU-bound сховища. Якщо системи дуже обмежені по CPU і обслуговують переважно нестискувані дані, подумайте про низьке або вимкнене стиснення для таких dataset-ів.

2) Який рівень zstd найкращий за замовчуванням?

Для багатьох загальних dataset-ів zstd-1 до zstd-3 — золота середина: помітна економія, невеликий наклад. Використовуйте вищі рівні лише після вимірювань покращення коефіцієнтів і прийнятної латентності.

3) Чому compressratio не змінився після встановлення нового рівня?

Тому що існуючі блоки зберегли своє початкове стиснення. Лише нові записи використовують нове налаштування. Щоб змінити історичні дані, потрібен churn або плановий rewrite (і зробіть snapshot перед цим).

4) Чи допомагає стиснення більше читанням чи записам?

Обидва можуть отримати користь. Записи можуть покращитись, бо менше байтів потрапляє на диск; читання можуть виграти, бо менше байтів знімається з диска і краще вміщується в кешах. Але стиснення витрачає CPU на запис (стиснення) і на читання (розпакування). У багатьох системах розпакування дешевше; стискання — центр витрат.

5) Чи завжди zstd кращий за lz4 на ZFS?

Ні. lz4 надзвичайно швидкий і часто «досить хороший». zstd на низьких рівнях може бути близьким за швидкістю, пропонуючи кращі коефіцієнти, але вибір залежить від запасу CPU і характеру навантаження. Якщо ви чутливі до латентності і утиснуті по CPU, lz4 може залишатися найнадійнішим дефолтом.

6) Як зрозуміти, що CPU завантажені через стиснення?

Шукайте високі значення CPU з низьким iowait, зростання write latency під сильними записами і покращення після зниження рівня стиснення на «гарячому» dataset-і. Використовуйте mpstat, iostat -x і zpool iostat разом, щоб триангуляціювати.

7) Чи знизить вищий рівень стиснення трафік реплікації?

Часто так, бо send-стріми відображають стиснені розміри блоків на диску, і стиснуті блоки менші. Але якщо ви перезаписали багато даних, щоб застосувати нове стиснення, тимчасово ви можете збільшити трафік реплікації через більший churn. Вимірюйте до та після в нормальних циклах.

8) Чи варто перетискати старі dataset-и після зміни рівня?

Лише якщо є бізнес-причина (нестача місця, дороге сховище, обмеження реплікації) і є вікно обслуговування. Rewrites генерують великий I/O і можуть взаємодіяти зі snapshots та фрагментацією. Часто безпечніше дозволити природному churn поступово переносити блоки.

9) Як recordsize впливає на вибір рівня zstd?

З більшими блоками ви часто отримуєте кращі коефіцієнти, і вищі рівні zstd можуть давати трохи більше вигоди. З маленькими блоками і випадковими записами вищі рівні можуть коштувати більше CPU при мінімальному виграші. Ось чому VM і DB dataset-и зазвичай тримаються на низьких рівнях.

10) Який найбезпечніший спосіб експериментувати в продакшені?

Зміни на рівні dataset, канарки і одна змінна за раз. Тримайте план відкату: ви завжди можете знизити рівень стиснення для нових записів негайно і відтермінувати перетискання старих блоків, поки не будете впевнені.

Висновок

Вибір рівнів zstd у ZFS — це не про пошук «найкращого числа». Це про розміщення вузького місця туди, де ви можете дозволити собі його. Низькі рівні zstd часто дають найкращий віддачу: стабільну економію простору, кращу ефективну пропускну здатність і мінімальний CPU-біль. Вищі рівні можуть бути виправдані — особливо для послідовних, холодних або бекап-орієнтованих dataset-ів — але лише після вимірювання, що маргінальні вигоди варті ризику CPU і латентності.

Якщо запам’ятати одне правило для операцій: налаштовуйте стиснення так само, як і будь-що в продакшені — в малому обсязі, з вимірюваними результатами, поетапно і з рутинним планом відкату. Ваш майбутній «я» у найгірший день кварталу скаже вам дякую.

← Попередня
Ubuntu 24.04: Fail2ban нічого не блокує — швидкий робочий процес перевірки
Наступна →
Debian 13: тайм-аути NFS — параметри монтування, що покращують стабільність (і коли ні)

Залишити коментар