Дедуплікація — це така функція, що здається ніби дає безкоштовні дивіденди, поки ваш пул не починає поводитися ніби під водою.
Найпоширеніший режим відмови — не «дедуплікація не працює». Це «дедуплікація працює, потім DDT не вміщується в RAM,
і кожен випадковий запис перетворюється на маленький пошук по диску».
Якщо ви тут через питання «Чи можна просто увімкнути дедуп?», то ви вже попереду. Правильна відповідь —
«Можливо, після того як ми спрогнозуємо розмір DDT і доведемо, що система витягне це». Зробімо це з цифрами, які можна
захистити в огляді змін.
DDT — що це (і чому боляче)
Дедуплікація в ZFS працює на рівні блоків: коли ви записуєте блок, ZFS обчислює його хеш і перевіряє, чи існує такий вміст.
Якщо існує, ZFS зберігає посилання замість ще однієї копії. Індекс, який це дозволяє, — це Deduplication Table (DDT).
Кожен унікальний блок має запис. Кожен спільний блок додає лічильники посилань.
Ця таблиця — не милий побічний елемент. Це критично важлива залежність шляху запису. При увімкненій дедуплікації запис
стає «хеш + пошук + можливо виділення + оновлення лічильників посилань». Якщо пошук по DDT швидкий (в ARC — потрапляння),
дедуп може бути прийнятним. Якщо пошук повільний (пропуск у ARC → читання з диска), продуктивність падає просто катастрофічно.
Операційна істина така: дедуплікація — переважно проблема підбору обсягу пам’яті, замаскована під фічу зберігання.
Вона також може бути проблемою по IOPS, затримці та «поясніть керівництву, чому бекапи запізнюються». Але все починається з RAM.
Ще одна річ, яку часто пропускають: увімкнення дедуплікації робиться на рівні dataset, але DDT фактично спільний для всього пула.
Один надто енергійний dataset може отруїти поведінку кеша всього пулу, роздмухавши робочий набір DDT.
Цікаві факти та контекст для зустрічей
- Дедуплікація передувала ZFS у сенсі ідеї: концепції зберігання за адресою вмісту та дедуп на основі хешів використовувалися в бекап-апаратах задовго до їхнього поширення у файлових системах.
- Ранні реалізації дедуп в ZFS заробили репутацію: багато перших впроваджень увімкнули її в загальних пулах і виявили, що «працює» і «швидко» — не синоніми.
- DDT відслідковує унікальні блоки, а не логічний розмір даних: два датасети по 1 ТБ можуть давати зовсім різні розміри DDT залежно від recordsize, стиснення та змінності даних.
- Стиснення змінює математику дедуп: ZFS хешує збережений блок (після стиснення), тому ідентичні несжаті дані, які стискаються по-різному, не дедупляться так, як ви очікуєте.
- Розмір блоку — це доля: менші recordsize збільшують кількість блоків, що підвищує число записів у DDT і потребу в RAM. Через це сховище для VM часто потрапляє в пастку дедуп.
- DDT — це метадані, але не всі метадані рівні: якщо ви додаєте special vdev для метаданих, DDT може опинитися там і зменшити випадкові операції вводу-виводу на повільних дисках.
- Дедуп не безкоштовний при читанні: він може посилити фрагментацію і додати рівні індикації, особливо після великої кількості знімків і видалень.
- Дедуп і шифрування не завжди дружать: якщо дані шифруються до того, як ZFS їх бачить (на рівні додатка), ідентичний plaintext виглядає по-різному і дедуп ефективно дорівнює нулю.
Правило великого пальця, яке звільнить вас з роботи (і те, що не звільнить)
Погане правило: «Дедуп потребує приблизно 1–2 ГБ RAM на ТБ». Ви почуєте це з впевненістю людини, яку через це колись викликали.
Чому це неправильно: воно припускає певний recordsize, певний коефіцієнт дублювання, певний патерн змінності даних і певний розмір запису DDT у пам’яті.
Змініть будь-який з них — і ваше «на ТБ» число стане вигадкою.
Хороше правило: плануйте RAM по записах DDT, а не по необроблених терабайтах. Оцініть кількість блоків,
оцініть кількість унікальних блоків, помножте на реалістичну пам’ять на запис, а потім застосуйте коефіцієнт робочого набору.
Якщо ви не вмієте оцінити кількість блоків — ви не готові увімкнути дедуп.
Жарт №1: Дедуп без підбору DDT — це як купувати вантажівку за об’ємом вантажу і ігнорувати обмеження на вагу мосту. Міст завжди переможе.
Обґрунтований метод підрахунку: оцінка кількості записів DDT і RAM
Крок 1: Оцініть, скільки блоків ви будете дедупити
Записи DDT приблизно масштабуються з кількістю унікальних блоків, записаних у дедуп-датасети.
Ви можете наближено визначити кількість блоків як:
Кількість блоків ≈ логічні байти, що посилаються / середній розмір блоку
«Середній розмір блоку» не обов’язково ваш recordsize або volblocksize, бо реальні блоки менші на кінцях файлів, метадані не рахуються однаково, і стиснення змінює збережений розмір. Але як планове число почніть із налаштованого розміру блоку для типу датасету:
- zvols для VM:
volblocksize(зазвичай 8K–32K у перформансних налаштуваннях) - Файлові датасети:
recordsize(зазвичай 128K за замовчуванням)
Крок 2: Оцініть частку унікальних блоків (dedup ratio)
Коефіцієнт дедуплікації показує, наскільки дані дублюються. Але для підрахунку DDT вам потрібне протилежне:
частка, яка є унікальною.
Приклад: якщо ви очікуєте dedup 2.0x, то близько 50% блоків унікальні. Якщо очікуєте 1.1x, то близько 91%
унікальні, тобто майже кожному блоку потрібен запис у DDT і ви майже нічого не заощадили.
Крок 3: Оцініть пам’ять DDT на запис
Формат запису DDT і накладні витрати в пам’яті залежать від версії OpenZFS, прапорів фіч та від того, чи ви рахуєте тільки on-disk запис,
чи структури в ARC (які включають хеш-таблиці, вказівники та поведінку витіснення). На практиці планувальники використовують консервативний діапазон.
Операційно безпечні планові числа:
- Мінімалістично оптимістичний: ~200 байт на унікальний блок (рідко безпечно для продакшену)
- Загальне планування: ~320 байт на унікальний блок
- Параноїдальне планування: 400–500 байт на унікальний блок (використовуйте для пулів з високою змінністю VM)
Якщо вас уже «підпалили» раніше, використовуйте параноїдальне планування. RAM дешевша за ваш час.
Крок 4: Застосуйте коефіцієнт робочого набору
DDT не має бути 100% резидентним, щоб функціювати, але продуктивність залежить від того, як часто шлях запису
потребує запису DDT, якого немає в ARC. Якщо ваше навантаження здебільшого послідовне і додаткове, інколи можна
обійтися частковим робочим набором DDT. Якщо навантаження — випадкові записи по великому простору адрес (привіт,
віртуалізація), вам потрібна велика частка DDT «гарячою» в ARC.
Практичні рекомендації:
- Зображення VM, бази даних, CI-ранери: ціль — 80–100% DDT в ARC робочому наборі
- Таргети бекапів, переважно послідовний інгест: 30–60% може бути допустимим, якщо DDT знаходиться на швидкому носії
- Змішані навантаження: приймайте гірший сценарій, якщо не можете ізолювати дедуп в окремий пул
Крок 5: Додайте запас для ARC, метаданих та решти ОС
Навіть якщо DDT поміщається, вам ще потрібен ARC для інших метаданих (dnode cache, dbufs), і RAM для ядра,
сервісів і піків навантаження. Перевантаження пам’яті призведе до того, що ZFS перестане кешувати перед тим, як почне свопити.
Тоді ваш пул починає поводитися ніби він персонально вас не любить.
Конкретний приклад
Припустимо, ви плануєте дедуплікацію 100 ТБ логічних даних у датасеті з recordsize 128K. Приблизна кількість блоків:
100 ТБ / 128K ≈ 800 мільйонів блоків. Якщо dedup ratio 2.0x, унікальних блоків ≈ 400 мільйонів.
RAM для DDT при 320 байт/запис: 400,000,000 × 320 ≈ 128 ГБ. Це тільки DDT. Якщо вам потрібно 80% резидентного робочого набору,
вам все одно знадобиться ~100 ГБ ARC доступного під нього, плюс решта.
Якщо ваш recordsize 16K, кількість блоків у 8 разів більша. Ті ж дані, той самий коефіцієнт dedup — і планування DDT виглядає як початковий внесок на будинок.
Ось чому розрахунок «на ТБ» вводить в оману.
Форми навантажень: коли дедуп корисний, а коли кусає
Добрі кандидати (іноді)
- Клони VDI з ідентичними базовими образами, де більшість блоків справді збігаються і залишаються стабільними.
- Репозиторії бекапів, куди пишуть великі повторювані блоки і рідко перезаписують старі дані.
- Сховища артефактів, де ті самі бінарні файли потрапляють регулярно і в основному незмінні.
Погані кандидати (часто)
- Загальне VM-сховище з малими блоками і постійною змінністю: оновлення ОС, swap, логи, бази даних.
- Бази даних, які часто перезаписують сторінки. Ви дедупите менше, ніж сподіваєтеся, і вічно платите за пошуки.
- Дані, зашифровані на джерелі (шифрування рівня додатка), що руйнує надмірність.
Змінність — тихий вбивця
Дедуп любить стабільні дублікати. Змінність міняє хеші. Навіть якщо ваш коефіцієнт dedup пристойний в певний момент, висока
змінність змушує часті оновлення DDT, підвищену ампліфікацію записів і більше випадкових I/O. Знімки можуть зберігати старі
блоки, збільшуючи DDT і фрагментацію пулу. Ваші «заощадження» стануть «метаданим боргом».
Special vdev, метадані та де фактично живе DDT
DDT зберігається на диску як частина метаданих пулу. Коли його немає в ARC, ZFS мусить отримати його з диска. Якщо той диск
— множина HDD, ваші дедуп-пошуки вишиковуються в чергу по 10 ms кожен. Ось як ви отримуєте багатосекундні затримки на пристойному обладнанні.
Special vdev може зберігати метадані (і опційно малі блоки), зокрема блоки DDT. Поміщення DDT на швидкий SSD/NVMe
може значно зменшити штраф, коли він випадає з ARC. Це не прибирає потребу в RAM, але може перетворити «катастрофічне» на «набридливе і вимірюване».
Мої упереджені рекомендації:
- Якщо ви розглядаєте dedup на жорстких дисках (HDD), плануйте special vdev або не робіть дедуп.
- Якщо у вас є special vdev, зеркальте його. Втрата special vdev може означати втрату пулу, залежно від конфігурації й того, що туди перемістилося.
- Не вважайте special vdev чарівним «акселератором дедуп». Це зменшувач затримки для промахів, а не заміна для ARC-попадань.
Практичні завдання: команди, виводи та рішення (12+)
Ось речі, які я реально запускаю перед тим, як хтось увімкне дедуп. Кожне завдання включає: команду, що означає вивід,
і яке рішення воно підштовхує. Замініть імена pool/датасетів відповідно до вашого оточення.
Завдання 1: Підтвердіть, що дедуп наразі вимкнений (або де він увімкнений)
cr0x@server:~$ zfs get -r -o name,property,value,source dedup tank
NAME PROPERTY VALUE SOURCE
tank dedup off default
tank/vm dedup off default
tank/backups dedup off default
Значення: Дедуп вимкнений у всіх показаних місцях. Якщо деякі датасети показують on, у вас вже є DDT.
Рішення: Якщо будь-який датасет має on, ви повинні виміряти існуючий DDT і його поведінку кеша перед розширенням використання.
Завдання 2: Перевірте прапори фіч пулу, релевантні для дедуп
cr0x@server:~$ zpool get -H -o property,value feature@extensible_dataset tank
feature@extensible_dataset active
Значення: Прапори фіч впливають на формат на диску і інколи на поведінку. Це підтверджує, що пул використовує сучасні фічі.
Рішення: Якщо ви на дуже старій версії пула або в режимі сумісності, перегляньте можливість dedup або плануйте міграцію спочатку.
Завдання 3: Зніміть recordsize / volblocksize для оцінки кількості блоків
cr0x@server:~$ zfs get -o name,property,value recordsize tank/backups
NAME PROPERTY VALUE
tank/backups recordsize 1M
Значення: recordsize 1M означає менше, більших блоків: DDT росте повільніше, ніж при 128K/16K навантаженнях.
Рішення: Роботи з великим recordsize більш дружні до дедуп з точки зору розміру DDT.
Завдання 4: Для zvols перевірте volblocksize (саме звідси починаються проблеми)
cr0x@server:~$ zfs get -o name,property,value volblocksize tank/vm/zvol0
NAME PROPERTY VALUE
tank/vm/zvol0 volblocksize 8K
Значення: Блоки 8K означають величезну кількість блоків для великого логічного обсягу. Це швидко надуває кількість записів DDT.
Рішення: Якщо ви плануєте дедуп для 8K zvols, рахувати варто з «параноїдальним» пам’яттю на запис і майже 100% робочим набором.
Завдання 5: Виміряйте referenced bytes (те, що дедуп має індексувати)
cr0x@server:~$ zfs list -o name,used,refer,logicalused,logicalrefer -p tank/vm
NAME USED REFER LOGICALUSED LOGICALREFER
tank/vm 54975581388800 54975581388800 87960930222080 87960930222080
Значення: Логічно посилані дані ≈ 80 ТБ. Розмір DDT корелює більше з логічними блоками, ніж з фізичними байтами.
Рішення: Використовуйте logicalrefer і розмір блоку для оцінки кількості блоків. Якщо є знімки, також врахуйте зростання referenced даних.
Завдання 6: Перевірте стиснення (воно змінює збережені блоки та ефективність дедуп)
cr0x@server:~$ zfs get -o name,property,value compression tank/vm
NAME PROPERTY VALUE
tank/vm compression lz4
Значення: LZ4 — добре. Стиснення може зменшити фізичний IO, але дедуп хешує стиснені блоки.
Рішення: Якщо стиснення вимкнене, подумайте про його включення перед dedup. Якщо стиснення вже добре зберігає місце, додатковий дедуп може дати мало маржі.
Завдання 7: Проаналізуйте розмір ARC і тиск (чи зможе він вмістити великий DDT?)
cr0x@server:~$ arcstat.py 1 3
time read miss miss% dmis dm% pmis pm% mmis mm% arcsz c
12:40:01 482 41 8 3 7% 8 20% 30 73% 96G 110G
12:40:02 501 45 9 4 9% 7 16% 34 76% 96G 110G
12:40:03 490 42 9 3 7% 6 14% 33 79% 96G 110G
Значення: ARC ≈ 96G з ціллю ≈ 110G. Пропусків близько 8–9% під час вибірки. Це непогано, але це ще не говорить про резидентність DDT.
Рішення: Якщо ARC вже обмежений, увімкнення дедуп буде конкурувати за кеш з іншими даними. Плануйте апгрейд RAM або ізолюйте дедуп в окремий пул.
Завдання 8: Перевірте використання swap (червоний прапор для планів дедуп)
cr0x@server:~$ free -h
total used free shared buff/cache available
Mem: 256Gi 142Gi 12Gi 3.0Gi 102Gi 104Gi
Swap: 16Gi 0.0Gi 16Gi
Значення: Swap не використовується. Добре. Якщо swap використовується під нормальним навантаженням — у вас вже дефіцит пам’яті.
Рішення: Якщо swap активний, не увімкнть dedup, поки не вирішите проблему з пам’яттю. Dedup + своп = легенда інцидентів.
Завдання 9: Оцініть потенціал дублювання без увімкнення дедуп (семплування хешами)
cr0x@server:~$ find /tank/backups -type f -size +128M -print0 | xargs -0 -n1 shasum | awk '{print $1}' | sort | uniq -c | sort -nr | head
12 0c4a3a3f7c4d5f0b3e1d6f1c3b9b8a1a9c0b5c2d1e3f4a5b6c7d8e9f0a1b2c
8 3f2e1d0c9b8a7f6e5d4c3b2a19080706050403020100ffeeddccbbaa998877
5 aabbccddeeff00112233445566778899aabbccddeeff001122334455667788
Значення: Ця груба вибірка показує дублікати великих файлів (один і той самий хеш зустрічається кілька разів). Це не дедуп на рівні блоків, але це індикатор.
Рішення: Якщо навіть на рівні файлів майже немає дублікатів — дедуп на рівні блоків, ймовірно, не окупить витрат.
Завдання 10: Якщо дедуп вже існує, виміряйте розмір DDT і попадання
cr0x@server:~$ zpool status -D tank
pool: tank
state: ONLINE
config:
NAME STATE READ WRITE CKSUM
tank ONLINE 0 0 0
raidz2-0 ONLINE 0 0 0
sda ONLINE 0 0 0
sdb ONLINE 0 0 0
sdc ONLINE 0 0 0
sdd ONLINE 0 0 0
sde ONLINE 0 0 0
sdf ONLINE 0 0 0
dedup: DDT entries 182345678, size 54.3G on disk, 76.9G in core
DDT histogram (aggregated over all DDTs):
bucket allocated referenced
______ ______________________________ ______________________________
refcnt blocks LSIZE PSIZE DSIZE blocks LSIZE PSIZE DSIZE
------ ------ ----- ----- ----- ------ ----- ----- -----
1 141M 17.6T 12.4T 12.5T 141M 17.6T 12.4T 12.5T
2 31.2M 3.9T 2.7T 2.7T 62.4M 7.8T 5.4T 5.5T
4 7.8M 1.0T 0.7T 0.7T 31.2M 4.0T 2.8T 2.8T
Значення: «in core» — це використання пам’яті для структур DDT, які зараз закешовані. Якщо це близько до доступного місця в ARC, ви живете небезпечно.
Гістограма показує, де дедуп виграє: відсіки з більшими refcount означають спільні блоки.
Рішення: Якщо «in core» конкурує з ARC за пам’ять і ваша затримка вже напружена, додавайте RAM або перемістіть DDT на швидший носій (special vdev).
Завдання 11: Слідкуйте за затримками та чергуванням під час навантаження (dedup це посилює)
cr0x@server:~$ iostat -x 1 3
avg-cpu: %user %nice %system %iowait %steal %idle
6.12 0.00 3.44 8.70 0.00 81.74
Device r/s w/s rkB/s wkB/s rrqm/s wrqm/s %util aqu-sz await
sda 12.0 95.0 512 8200 0.0 2.0 84.0 6.2 55.1
sdb 10.0 90.0 488 7900 0.0 1.0 79.0 5.7 50.3
Значення: Високе await і зростаючий aqu-sz вказують на чергування на дисках. Промахи дедуп додають більше випадкових читань, збільшуючи черги.
Рішення: Якщо ви вже сильно загружуєте диски, дедуп, ймовірно, погіршить затримки, якщо не перемістити DDT-читання на швидke сховище і не тримати його «гарячим» в ARC.
Завдання 12: Підтвердіть наявність special vdev та ashift (план швидкості метаданих)
cr0x@server:~$ zpool status tank
pool: tank
state: ONLINE
config:
NAME STATE READ WRITE CKSUM
tank ONLINE 0 0 0
raidz2-0 ONLINE 0 0 0
sda ONLINE 0 0 0
sdb ONLINE 0 0 0
sdc ONLINE 0 0 0
sdd ONLINE 0 0 0
sde ONLINE 0 0 0
sdf ONLINE 0 0 0
special
mirror-1 ONLINE 0 0 0
nvme0n1 ONLINE 0 0 0
nvme1n1 ONLINE 0 0 0
Значення: Існує mirrored special vdev. Добре. Це ваш «швидкий коридор для метаданих».
Рішення: Якщо плануєте dedup, перевірте, що блоки DDT можуть потрапити на special vdev і що він має ресурс endurance і запас ємності.
Завдання 13: Перевірте налаштування special_small_blocks (щоб випадково не перемістити те, чого не хотіли)
cr0x@server:~$ zfs get -o name,property,value special_small_blocks tank
NAME PROPERTY VALUE
tank special_small_blocks 0
Значення: Лише метадані йдуть на special vdev; малі блоки даних не переміщуються. Це безпечніше для планування ємності.
Рішення: Розгляньте залишити його 0, якщо у вас немає чіткого плану і моделі ємності. Переміщення малих блоків на special може бути чудом або катастрофою залежно від заповнення.
Завдання 14: Змоделюйте кількість записів DDT з розміром блоку і логічними даними
cr0x@server:~$ python3 - <<'PY'
logical_tb = 80
block_kb = 8
dedup_ratio = 1.3
logical_bytes = logical_tb * (1024**4)
block_bytes = block_kb * 1024
blocks = logical_bytes / block_bytes
unique_blocks = blocks / dedup_ratio
for bpe in (320, 450):
ddt_gb = unique_blocks * bpe / (1024**3)
print(f"blocks={blocks:,.0f} unique={unique_blocks:,.0f} bytes_per_entry={bpe} => DDT~{ddt_gb:,.1f} GiB")
PY
blocks=10,737,418,240 unique=8,259,552,492 bytes_per_entry=320 => DDT~2,462.0 GiB
blocks=10,737,418,240 unique=8,259,552,492 bytes_per_entry=450 => DDT~3,461.9 GiB
Значення: Це вивід «не робіть цього». 80 ТБ при 8K блоках і всього 1.3x dedup дає багатотерабайтну потребу в пам’яті DDT. Це не проблема налаштування.
Рішення: Не ввімкнюйте дедуп на такому навантаженні. Змініть дизайн: більші блоки, інша техніка зберігання або прийміть вартість ємності.
Завдання 15: Перевірте кількість знімків і потенціал змінності
cr0x@server:~$ zfs list -t snapshot -o name,used,refer -S creation | head -n 5
NAME USED REFER
tank/vm@daily-2025-12-26 0 80T
tank/vm@daily-2025-12-25 0 79T
tank/vm@daily-2025-12-24 0 79T
tank/vm@daily-2025-12-23 0 78T
Значення: Багато знімків можуть закріплювати старі блоки, тримаючи записи DDT живими і перешкоджаючи звільненню простору. Навіть «USED 0» знімки можуть представляти великі referenced дерева.
Рішення: Якщо зберігання знімків довге і змінність висока, припускайте, що DDT зростає і залишається великим. Розгляньте обмеження дедуп до датасетів з контрольованими політиками знімків.
Швидкий план діагностики: знайти вузьке місце за кілька хвилин
Коли пули з дедуп увімкненим повільніють, люди роблять припущення. Не робіть так. Ось найшвидший шлях до істини, по порядку.
Перше: Чи вміщується DDT в ARC або відбувається трешінг?
- Запустіть
zpool status -Dі подивіться на розмір «in core». Якщо він величезний відносно доступного ARC — ризик високий. - Перевірте статистику ARC під час навантаження (
arcstat.py): якщо miss% підскакує при наростанні записів — це ваш знак. - Шукайте стійку високу затримку навіть при низькому пропуску: класичний симптом блокувань метаданих, що затримують записи.
Друге: Чи попадають промахи на повільні носії?
- Запустіть
iostat -xі дивітьсяawait/aqu-szна vdev. - Якщо у вас є special vdev, перевірте, чи саме він завантажений. Якщо HDD навантажені — DDT, ймовірно, читається з «руста».
- Низький CPU + високе iowait + високе disk await — підпис болю дедуп.
Третє: Чи система страждає від нестачі пам’яті або свопиться?
free -hіvmstat 1: будь-яка активність свопу під нормальним навантаженням — червоний прапор.- Якщо ARC жорстко обмежений або швидко зменшується — дедуп стане гіршим через витіснення DDT.
Четверте: Чи просто навантаження — поганий кандидат для дедуп?
- Перевірте гістограму DDT: якщо більшість блоків має refcnt=1, дедуп — переважно накладні витрати.
- Перевірте коефіцієнт dedup з
zfs get dedup(якщо вже увімкнено) і порівняйте з очікуваннями. - Якщо dedup ~1.0x–1.2x — ви платите багато, щоб заощадити дуже мало.
Якщо ви застрягли: захопіть короткий знімок продуктивності під навантаженням і вирішіть, чи ви в дефіциті пам’яті (промахи DDT),
IOPS (черги дисків) або в архітектурному дефіциті (низьке дублювання). Не налаштовуйте наосліп.
Поширені помилки: симптом → корінь проблеми → виправлення
1) Записи стають рваними і повільними після увімкнення дедуп
Симптом: Зростає затримка, пропуск падає, CPU спокійний, диски показують випадкові читання.
Корінь проблеми: Робочий набір DDT не вміщується в ARC; пошуки дедуп пропускаються і читаються блоки DDT з диска.
Виправлення: Додати RAM (реальне виправлення), або перемістити метадані/DDT на mirrored special vdev (пом’якшення), або вимкнути дедуп і перезаписати дані без дедуп (болісно, але чесно).
2) Коефіцієнт дедуп розчаровує (біля 1.0x), але продуктивність все одно гірша
Симптом: Пул уповільнився; економія місця мінімальна.
Корінь проблеми: Навантаження має низьку істинну дублювання (шифровані дані, по-різному стиснені, висока змінність), але дедуп усе одно змушує робити пошуки і оновлення лічильників посилань.
Виправлення: Припиніть використання дедуп для цього датасету. Використовуйте стиснення, кращий вибір recordsize або дедуп на рівні додатка (бекап-пЗ).
3) Пул працював нормально тижнями, потім раптово погіршився «без причини»
Симптом: Пул з дедуп деградує з часом; перезавантаження тимчасово допомагають.
Корінь проблеми: DDT зростає з новими унікальними блоками, знімки закріплюють старі блоки, тиск на ARC зростає до моменту, коли промахи домінують.
Виправлення: Перегляньте політику зберігання і змінність. Додайте RAM, скоротіть зберігання знімків на дедуп датасетах і переконайтеся, що DDT на швидкому носії. Розділіть навантаження по окремих пулах.
4) Special vdev заповнюється і пул панікує операційно
Симптом: Special vdev досягає високої заповненості; алокації метаданих відмовляють; продуктивність падає.
Корінь проблеми: Неправильно підібраний розмір special vdev, або special_small_blocks перемістило більше даних, ніж очікували, або зростання метаданих дедуп перевищив план.
Виправлення: Плануйте ємність special vdev з запасом. Зеркальте його. Якщо він вже занадто малий — мігруйте дані в новий пул; розширення special vdev не завжди тривіальне залежно від розмітки.
5) «Ми просто додамо RAM пізніше» перетворюється на математику простою
Симптом: Затвердження змін припускає, що RAM можна додати без впливу, але вікна технічного обслуговування обмежені.
Корінь проблеми: Дедуп увімкнено без жорсткого бюджету ємності/продуктивності; тепер відкотитися складно, бо дані вже дедуплені.
Виправлення: Ставтеся до дедуп як до архітектурного рішення. Якщо потрібно тестувати — робіть це на клоні пулу або обмеженому датасеті з планом відкату.
Три корпоративні міні-історії з польових боїв
Міні-історія 1: Інцидент через неправильне припущення
Середня компанія консолідувала «різне сховище» в один ZFS пул. Він хостив VM-образи, артефакти CI і кілька бекап-директорій. Команда побачила дублікати ISO і повторювані шаблони VM і вирішила, що дедуп — це легкий виграш. У заяві на зміну було по суті: «дедуп зменшить використання місця; вплив на продуктивність очікується мінімальний».
Неправильне припущення було тонким: вони розрахували дедуп за сирими ТБ і припустили скромні накладні витрати RAM. Вони не змоделювали кількість блоків. На боці VM були zvols з малими блоками і випадковим патерном записів. Через години тривоги по затримці почали спрацьовувати по різних системах. Збірки сповільнились. Консолі VM інколи зависали. Ніхто не міг швидко зв’язати це, бо нічого «великого» не змінилося — не додавали нового обладнання, не випускали реліз.
On-call SRE зняв базову телеметрію: CPU був спокійний, мережа не навантажена, диски кричали. Випадкові читання на HDD-відсіках підскочили, і середній await пішов у десятки мс. Система не була переповнена місцем. Вона була без швидких метаданих. Пошуки DDT пропускали ARC і потрапляли на «руст».
Виправлення не було хитрим. Вони вимкнули дедуп для майбутніх записів і почали мігрувати найгірших винуватців у пул без дедуп. Це зайняло час, бо існуючі дедуплені блоки не «роздедупляться» без перезапису. Постмортем вирішив: зміни дедуп вимагають оцінки DDT на основі кількості блоків і змінності, переглянутої як план ємності, а не як перемикач функції.
Міні-історія 2: Оптимізація, що повернулася бумерангом
Інша організація вирішила поскладати. Вони знали, що пошуки дедуп дорогі, тому додали special vdev на швидкі SSD і включили special_small_blocks, щоб перемістити малі блоки теж, аргументувавши, що «мале випадкове IO має йти на SSD». На папері це виглядало як інженерія продуктивності.
Насправді їхні навантаження мали багато малих блоків. Не лише метадані, а дані: логи, кеші пакетів, малі артефакти і файловий шум VM. Special vdev почав заповнюватись швидше, ніж хтось прогнозував. Коли він наближався до неприємного заповнення, поведінка виділення стала напруженою. Затримки стали нестабільними, і операційний ризик зріс:
special vdev став критичним для значно більшої частини датасету, ніж передбачалося.
Повернення бумерангом не в тому, що SSD погані. Воно в тому, що вони використовували special vdev як смітник продуктивності. Вони змішали цілі (прискорити метадані, прискорити малі блоки, пришвидшити dedup) без єдиної моделі ємності.
Коли так робиш — у тебе не дизайн, а несподіваний підпис.
План відновлення був нудним, але болючим: міграція в новий пул з правильно підібраним special vdev, консервативне налаштування special_small_blocks, і використання дедуп лише для датасетів з доведеним дублюванням. Продуктивність покращилася, але справжній виграш був у тому, що ризик став зчитуваним і передбачуваним.
Міні-історія 3: Нудна, але правильна практика врятувала день
Велика внутрішня платформа хотіла дедуп для VDI-подібного середовища, де базові образи були ідентичні, а цикли патчів передбачувані. Їх підкушувало увімкнути дедуп широко, але один інженер наполіг на поетапному підході:
створити окремий пул для кандидатів на дедуп, зібрати тиждень трас навантаження і розрахувати RAM за консервативним bytes-per-entry з запасом.
Вони почали з пілоту: підмножина десктопів і лише томи, що походили від шаблонів. Щодня дивилися zpool status -D,
відстежували ARC hit ratios під піковими логінами і вимірювали затримку на шарі гіпервізора. Також встановили жорсткі критерії відкату: якщо 95-й перцентиль затримки запису перевищував поріг більше ніж кілька хвилин, пілот зупинявся і дані перенаправлялися.
Нічого драматичного не сталося. Ось у чому суть. DDT виріс, як передбачалося, ARC залишався здоровим, і special vdev обробляв випадкові промахи, не втягуючи HDD у бій. Економія дедуп була реальною, бо навантаження справді дублювалося і було досить стабільним.
Коли керівництво питало, чому розгортання зайняло довше, ніж просто перемикання прапора, відповідь була проста: «Ми заплатили за впевненість». Нудна практика — пілот + вимірювання + консервативне планування — врятувала їх від перетворення проєкту ємності в інцидент.
Чеклісти / покроковий план
Перш ніж запросити зміну (pre-flight checklist)
- Перелічіть кандидати-датасети і підтвердіть зону застосування дедуп. Не ввімкніть випадково pool-wide.
- Занотуйте розміри блоків:
recordsizeдля файлів,volblocksizeдля zvols. - Виміряйте
logicalreferдля кожного датасету і політики зберігання знімків. - Оцініть реалістично коефіцієнт дедуп (вибірка або відомі патерни навантаження, як VDI).
- Обчисліть очікувані унікальні блоки і RAM для DDT (звичайні та параноїдальні байти на запис).
- Перевірте поточний запас ARC і тиск пам’яті системи.
- Вирішіть, куди потраплятимуть промахи DDT: HDD vs special vdev vs all-flash.
- Запишіть критерії відкату: пороги затримки, пороги пропусків промахів, тригери бізнес-імпакту.
План пілоту (безпечний спосіб навчитися)
- Створіть виділений датасет (або пул) для кандидатів на дедуп.
- Увімкніть дедуп лише на цьому датасеті і перемістіть репрезентативну підмножину даних.
- Щодня моніторьте зростання DDT через
zpool status -Dі співвідношення «in core» до розміру ARC. - Вимірюйте затримку на рівні додатків, де це відчувають користувачі (затримка VM IO, час commit DB), а не лише ZFS-метрики.
- Навмисно створіть піковий період (підняття сесій, вікно батчу) і спостерігайте найгіршу поведінку.
- Розширюйте охоплення тільки після того, як зможете прогнозувати зростання DDT з часом, а не лише за перший день.
План розгортання в продакшн (на що я підписався б)
- Переконайтесь, що обсяг RAM задовольняє консервативну ціль робочого набору DDT плюс запас ARC.
- Переконайтесь, що special vdev (якщо є) зеркалено і має значний запас ємності для зростання метаданих.
- Увімкніть дедуп лише на обмеженому наборі датасетів; не дозволяйте спадкувати його всюди, якщо вам не потрібні сюрпризи.
- Встановіть політики збереження знімків явно для дедуп-датасетів, щоб контролювати довгострокове зростання DDT.
- Заплануйте перевірки після зміни (1 день, 1 тиждень, 1 місяць) з тими самими метриками кожного разу.
Жарт №2: Дедуп — єдина фіча, де економія місця може коштувати вам часу, грошей і думки кількох нових співробітників.
FAQ
1) Чи можу я точно спрогнозувати розмір DDT перед увімкненням дедуп?
Точно — ні. Ви можете спрогнозувати достатньо добре, щоб прийняти безпечне рішення, оцінюючи кількість блоків, частку унікальних блоків
і застосовуючи консервативні байти на запис. Пілотний підхід наближає вас до «точного», бо вимірює реальну поведінку з часом.
2) Чи завжди справедливо, що «DDT має поміститися в RAM»?
Для доброї продуктивності при випадкових записах — функціонально так: гарячий робочий набір має вміщатися. Якщо навантаження
здебільшого послідовне і блоки DDT зберігаються на швидкому носії, часткова резидентність може бути прийнятною. Але «прийнятно»
не означає «приємно».
3) Яке розумне число байт на запис DDT?
Використовуйте 320 байт як базове планове значення і 400–500 байт для навантажень з високою змінністю і малими блоками.
Якщо вибір впливає на рішення — вибирайте більше і спокійніше спіть.
4) Чи допомагає стиснення або шкодить дедуп?
Воно може допомогти за ємністю і знизити фізичний IO, але може зменшити збіги дедуп, якщо «схожі» дані стискаються в різні послідовності байт.
Пам’ятайте: ZFS дедуп хешує збережений блок, який зазвичай стиснений.
5) Якщо я увімкнув дедуп і пожалівся, чи безпечно його вимкнути?
Ви можете вимкнути дедуп для майбутніх записів, встановивши dedup=off на датасеті. Існуючі дедуплені блоки залишаються дедупленими, поки не будуть перезаписані.
Повернутися до повністю недедупленого стану зазвичай означає копіювання даних у недедуп датасет (або новий пул) і нарізку.
6) Чи вирішить special vdev мої проблеми з дедуп?
Це допоможе, зробивши промахи DDT/метаданих менш болісними. Воно не замінить RAM. Якщо у вас високий рівень промахів DDT, ви все одно платите за IO і затримку;
ви просто платите її на NVMe замість HDD.
7) Чи варто вмикати дедуп для VM-сховища?
Зазвичай ні, якщо у вас немає дуже специфічного, стабільного патерну дублювання (як клони VDI) і ви змоделювали розмір блоку і змінність.
Для загальних VM-ферм безпечніше використовувати стиснення + хороші шаблони + thin provisioning.
8) Які метрики доводять, що дедуп вартий того?
Дві категорії: ємність і затримка. Ємність: значущий коефіцієнт dedup (не ледь більше 1.0x) і стабільний з часом.
Затримка: p95/p99 IO-затримки залишаються в межах SLO під піковими періодами запису. Якщо будь-яка з цих категорій провалюється — дедуп невигідний.
9) Чи взаємодіє дедуп зі знімками?
Так. Знімки закріплюють старі блоки, що тримає записи DDT живими і може збільшувати фрагментацію. Довге зберігання знімків плюс висока змінність —
класичний рецепт зростання DDT і погіршення тиску кеша з часом.
10) Який найбезпечніший спосіб спробувати дедуп у продакшн?
Не «пробуйте» широко. Пілотуйте на ізольованому датасеті (або окремому пулі), з явними критеріями відкату, і вимірюйте зростання DDT та затримки під реальними піками.
Висновок: наступні кроки, що не зіпсують вам вихідні
Дедуп — це не пункт у чеклісті. Це зобов’язання носити великий, критичний для продуктивності індекс у пам’яті і тримати його
настільки «гарячим», щоб шлях запису не перетворився на терапію випадкових I/O.
Практичні наступні кроки:
- Інвентаризуйте кандидати-датасети і зафіксуйте їхні розміри блоків (
recordsize/volblocksize). - Виміряйте
logicalreferі політику знімків, щоб зрозуміти, скільки блоків вам справді індексувати. - Змоделюйте RAM для DDT з консервативними байтами на запис і підходящим коефіцієнтом робочого набору.
- Якщо математика жахлива — повірте їй. Змініть дизайн: не використовуйте дедуп, ізолюйте його або переходьте до навантаження з реальною дублюванням.
- Якщо математика виглядає прийнятною — запустіть пілот з жорсткими критеріями відкату і спостерігайте зростання «in core» DDT з часом.
Одну перефразовану ідею від відомого голосу надійності варто нагадати тут: «Надія — не стратегія», у дусі операційних мислителів.
Розмірюйте DDT так само, як ризик: з доказами, запасом і планом відкату.