Ви увімкнули dedup у ZFS, бо хтось сказав, що це «безкоштовне місце». Потім ваш пул почав поводитися так, ніби він переадресовує кожен I/O-запит на збір ради.
Стрибки затримки. Записи повзають. Перезавантаження відчуваються як рулетка. І коробка, що раніше просто була гарячою, тепер постійно зайнята.
Злочинець рідко в абстракті — “dedup”. Це таблиці дедуплікації (DDT): де вони живуть, який у них розмір, як часто ви пропускаєте кеш і наскільки брутально
ZFS піде на диск, щоб виконати свої обіцянки.
DDT простими словами: що це
Дедуплікація ZFS працює, помічаючи, що два блоки ідентичні, і зберігає лише одну фізичну копію. У теорії — чудово. На практиці, щоб не втратити дані,
ZFS має бути абсолютно впевненим, що вже бачив цей блок. Ця впевненість походить із структури, схожої на базу даних: Deduplication Table, або DDT.
DDT — це, по суті, великий індекс, ключований за контрольною сумою блоку (і з додатковими метаданими). Коли надходить запис, ZFS обчислює контрольну суму і питає DDT:
«Чи маю я вже цей блок десь?» Якщо так — збільшує лічильник посилань і не записує ще одну копію. Якщо ні — записує новий блок і додає запис у таблицю.
Це означає, що DDT знаходиться на гарячому шляху для кожного запису з увімкненим dedup. Не «інколи». Кожного разу. І оскільки ZFS — це ZFS, він буде підтримувати цю таблицю правильно,
навіть якщо це боляче. Особливо якщо боляче.
Перше, що потрібно зрозуміти: dedup — це не опція, яку ви щедро розподіляєте по датасетах. Це зобовʼязання виконувати пошук у таблиці для блоків і справлятися
з наслідками по пам’яті та I/O назавжди — доки ви не перезапишете дані без dedup.
Чому DDT шкодить: реальна модель витрат
1) DDT хоче RAM, як малюк хоче перекусів
Записи DDT — це метадані. Метадані хочуть бути в пам’яті, бо їх читання з диска знову й знову повільне і нестабільне. Коли робочий набір записів DDT вміщується
в ARC (кеш ZFS), dedup може бути «доволі прийнятним». Коли ні — ви отримуєте кеш-промахи DDT, що означає додаткові випадкові читання, а отже затримки і роздратованих
власників додатків.
ZFS продовжуватиме працювати з DDT, що не вміщується в RAM. Просто працюватиме, ніби йому надягли гирі на щиколотки під час ходьби вгору по схилу під дощем.
2) Пошуки в DDT перетворюють послідовні записи на випадкові читання
Без dedup стрімінгове навантаження може бути здебільшого послідовним записом. З dedup послідовність така:
обчислити контрольну суму → звернутись до DDT → можливо прочитати DDT з диска → потім записати (або ні). Такий шаблон пошуку часто випадковий, і відбувається під час запису.
Випадкові читання на HDD — це податок. На SSD — менший податок, але рахунок усе одно приходить.
3) «Зекономили 30% місця» — це не бюджет продуктивності
Мірило успіху dedup — це зекономлене місце. Мірило успіху продакшну — стабільна затримка під навантаженням. Вони повʼязані, але не співпадають.
Ви можете мати відмінний dedup-коефіцієнт і водночас жахливу продуктивність, бо DDT не вміщується, або тому що сховище занадто повільне для швидкості пошуків.
4) Dedup змінює режими відмов
З dedup кілька логічних блоків вказують на один фізичний блок. Це безпечно — ZFS використовує copy-on-write і контрольні суми — але це підвищує ставки щодо здоровʼя метаданих
і здатності системи отримувати доступ до записів DDT. Ви все ще зможете відновитися після відмови пристрою; просто ви не захочете робити це з виснаженим ARC і DDT,
що гуркотить на диск при кожній групі транзакцій.
5) Прихована «довгострокова вартість»
Болючий момент — не лише увімкнення dedup. Це життя з ним. Після того, як дані записані з dedup=on, вимкнення dedup=off не знімає дедуплікацію з уже існуючих блоків.
Ви зобовʼязані цій on-disk структурі DDT, поки не перезапишете дані (send/receive на пул без dedup або скопіювати і повернути).
Одна суха операційна істина: якщо ви ввімкнете dedup необачно, згодом ви заплануєте «проект міграції даних», який по суті є виплатою за кредит, про який ви не підозрювали.
Ось цитата на дорогу, бо вона підходить ідеально:
Надія — це не стратегія.
— перефразована ідея, яку часто приписують лідерам операцій
Факти та історичний контекст (коротко, конкретно)
- Dedup зʼявився щоб вирішити реальну проблему: ранні ферми VM та бекапи мали багато дублікатів блоків між образами і повними бекапами.
- Dedup у ZFS працює на рівні блоків, не файлів: він не дивиться на імена файлів, а на фіксовані блоки запису (а також деякі змінні випадки).
- DDT зберігається на диску: це не «просто кеш». ARC тримає робочі набори, але канонічна таблиця живе в пулі.
- Dedup у ZFS — властивість датасету: але DDT — реальність на рівні пулу. Декілька датасетів з dedup ділять одні й ті ж структурні DDT.
- Вибір контрольної суми важливий: сучасні ZFS за замовчуванням використовують сильні контрольні суми; dedup покладається на них, і страх колізій — одна з причин, чому це не «дешево».
- Ранні поради були грубими: багато адміністраторів вчили «1–2GB RAM на TB дедуплікації» як правило великого пальця, а потім виявляли, що реальність залежить від навантаження.
- Облік DDT покращився з часом: пізніші версії OpenZFS показують кращі гістограми та статистику, щоб точніше оцінити вплив на памʼять.
- Спеціальні vdev змінили розмову: розміщення метаданих (включно з DDT) на швидких пристроях може допомогти, але це не безкоштовний квиток і має свої небезпеки.
- Компресія відібрала обід у dedup у багатьох організаціях: для сучасних даних lz4 часто дає помітну економію з набагато меншою волатильністю продуктивності.
Як дедуплікація насправді працює (і де DDT вписується)
Dedup — це задача пошуку під виглядом функції економії місця
На високому рівні потік дедуплікації виглядає так:
- Формується вхідний логічний блок (розмір recordsize для файлових систем, volblocksize для zvol).
- Обчислюється контрольна сума (і опціонально застосовується стиснення; точний порядок залежить від конфігурації та реалізації).
- Запит до DDT: чи існує ця контрольна сума, і чи відповідає вона метаданим блоку?
- Якщо знайдено — refcount збільшується; логічний блок вказує на існуючий фізичний блок.
- Якщо не знайдено — блок записується, у DDT додається новий запис.
Що приблизно означає запис DDT
Запис DDT — це не просто «контрольна сума → вказівник блоку». Він також містить достатньо інформації, щоб:
перевірити відповідність, знайти фізичний блок і відстежувати, скільки логічних посилань на нього вказують.
Ось чому витрати памʼяті не тривіальні. DDT ближчий до індексу в базі даних, ніж до простого хеш-словника.
Чому промахи критичніші, ніж звичайні кеш-промахи
Багато кешів іноді промахують, і система виживає. Промах DDT особливий, бо він на шляху запису і має тенденцію викликати випадкові I/O. Звичайний промах кеша читань може
затримати читання. Промах DDT додає затримку читання перед тим, як запис взагалі зможе вирішити, що робити.
На завантаженій системі це означає накопичення черг, довші txg sync-часи і, зрештою, знайому симптоматику: все «зависає» хвилями, потім відновлюється, потім знову зависає.
Ця картина — класичний «метаданний треш», і DDT — одна з найшвидших доріг туди.
Dedup-коефіцієнт — не ваша мета; робочий набір DDT — ось що важливо
Dedup-коефіцієнт (логічне vs фізичне) показує вигоду. Робочий набір DDT показує експлуатаційну вартість. Хочете обидва. Рідко отримуєте обидва.
Жарт №1: Dedup — це як купити більший чемодан, щоб не платити за багаж, а потім виявити, що сам чемодан важить 20 кілограмів.
Швидкий план діагностики
Коли пул з dedup повільний, ви можете витратити дні на суперечки про «розмір ARC», «SLOG», «sync», «мережу» або «ті диски старі».
А можна спочатку перевірити шлях DDT і швидко вирішити, чи ви в пеклі пошуків.
По-перше: підтвердіть, що dedup дійсно працює
- Перевірте властивість dedup на датасетах і zvol, куди йдуть записи.
- Перевірте, чи пул має нетривіальний DDT (якщо dedup був увімкнений раніше).
По-друге: перевірте, чи DDT вміщується в кеш
- Подивіться розмір DDT, гістограму і чи часто записи DDT відсутні в ARC.
- Подивіться на тиск ARC і поведінку видалення (eviction).
По-третє: доведіть, що вузьке місце — випадкові читання
- Порівняйте iostat: чи бачите підвищені read IOPS під час інтенсивних записів?
- Перевірте затримки: випадкові читання стрибають, коли шлях пошуку DDT йде на диск.
- Корелюйте з txg sync-часами і CPU часом у шляхах checksum/compress.
По-четверте: вирішіть шлях відступу
- Якщо DDT не вміщується і ви не можете додати RAM або швидкі метадані-пристрої, плануйте міграцію з dedup.
- Якщо DDT керований, налаштуйте розміри записів, шаблони навантаження і подумайте про special vdev / швидше сховище.
Практичні завдання: команди, виводи, що означають і як приймати рішення
Нижче — практичні завдання, які можна виконати на типовому Linux OpenZFS хості. Команди реалістичні; виводи — приклади. Ваші поля і числа можуть відрізнятися залежно від версії та дистрибутива.
Завдання 1: Знайти, де увімкнено dedup (і де ви забули, що увімкнули)
cr0x@server:~$ zfs get -r -o name,property,value,source dedup tank
NAME PROPERTY VALUE SOURCE
tank dedup off default
tank/vm dedup on local
tank/vm/win10 dedup on inherited from tank/vm
tank/home dedup off default
Що це означає: записи в tank/vm та дочірніх датасетах робитимуть пошуки в DDT. tank/home — ні.
Рішення: якщо dedup «on» десь є, опишіть робочі навантаження там. Якщо він «on» для загального набору датасетів, припускайте неправильну конфігурацію, поки не доведено інше.
Завдання 2: Перевірити, чи існуючі дані вже дедупліковані (властивість dedup бреше про історію)
cr0x@server:~$ zdb -DD tank
DDT-sha256-zap-duplicate: 123456 entries, size 350 on disk, 180 in core
DDT-sha256-zap-unique: 987654 entries, size 2100 on disk, 1200 in core
DDT histogram (aggregated over all DDTs):
bucket allocated referenced
______ ______________________________ ______________________________
refcnt blocks LSIZE PSIZE DSIZE blocks LSIZE PSIZE DSIZE
----- ------ ----- ----- ----- ------ ----- ----- -----
1 900K 110G 72G 72G 900K 110G 72G 72G
2 80K 10G 6G 6G 160K 20G 12G 12G
4 10K 2G 1G 1G 40K 8G 4G 4G
Що це означає: пул вже містить дедупліковані блоки (існують записи DDT). Вимкнення dedup зараз не видалить їх.
Рішення: якщо DDT значущий і продуктивність погана, вам потрібен план перезапису/міграції, а не просто переключення властивості.
Завдання 3: Швидка перевірка «чи це того варте?» (коефіцієнт проти болю)
cr0x@server:~$ zpool get dedupratio tank
NAME PROPERTY VALUE SOURCE
tank dedupratio 1.14x -
Що це означає: 1.14x — помірна економія. На петабайтах може бути значущою, але на середніх пулах рідко варта операційного хаосу.
Рішення: якщо dedupratio близький до 1.0x і ви платите за затримки, плануйте вихід з dedup, якщо немає дуже конкретної причини залишити його.
Завдання 4: Перевірити розмір ARC і тиск (чи голодує DDT?)
cr0x@server:~$ cat /proc/spl/kstat/zfs/arcstats | egrep "^(size|c |c_min|c_max|memory_throttle_count|arc_no_grow|demand_data_hits|demand_data_misses) "
size 4 25769803776
c 4 34359738368
c_min 4 8589934592
c_max 4 68719476736
arc_no_grow 4 0
memory_throttle_count 4 12
demand_data_hits 4 91522344
demand_data_misses 4 1822331
Що це означає: ARC ≈24GiB, ціль ≈32GiB, макс ≈64GiB; було memory throttling (тиск). DDT конкурує з усім іншим.
Рішення: якщо сервер обмежений по памʼяті або спостерігається часте throttling, dedup — поганий сусід. Додайте RAM, зменште навантаження або вийдіть з dedup.
Завдання 5: Виміряти затримку пулу і read IOPS під час записів (тест-підозра DDT)
cr0x@server:~$ iostat -x 1 5
avg-cpu: %user %nice %system %iowait %steal %idle
6.20 0.00 5.10 9.80 0.00 78.90
Device r/s w/s rkB/s wkB/s avgrq-sz avgqu-sz await r_await w_await svctm %util
nvme0n1 320.0 180.0 9200.0 6400.0 56.0 4.20 10.8 9.4 13.3 0.9 45.0
sda 90.0 20.0 1100.0 400.0 27.0 8.80 78.0 85.0 45.0 7.2 79.0
sdb 95.0 22.0 1200.0 420.0 28.0 9.10 81.0 88.0 47.0 7.4 82.0
Що це означає: багато читань відбувається тоді, коли ви очікуєте переважно записи, і час очікування читань великий на HDD. Це відповідає DDT-пошукам, які пропускають ARC.
Рішення: якщо бачите тиск випадкових читань, привʼязаний до сплесків записів, вважайте промахи DDT головним підозрюваним і підтвердіть це за статистикою DDT/гістограмами.
Завдання 6: Підтвердити recordsize/volblocksize і чому це важливо для dedup
cr0x@server:~$ zfs get -o name,property,value recordsize tank/vm
NAME PROPERTY VALUE
tank/vm recordsize 128K
Що це означає: більші блоки означають менше записів DDT для того самого обсягу даних, але можуть зменшити можливості дедуплікації і вплинути на патерни випадкового I/O.
Рішення: для VM zvol розгляньте узгодження volblocksize з навантаженням і уникайте крихітних блоків, якщо немає причин. Але не намагайтеся «налаштуванням» вирішити недостатній ARC.
Завдання 7: Перевірити, чи стиснення може замінити dedup для вашого навантаження
cr0x@server:~$ zfs get -o name,property,value compression,compressratio tank/vm
NAME PROPERTY VALUE
tank/vm compression lz4
tank/vm compressratio 1.48x
Що це означає: ви вже отримуєте 1.48x від стиснення, яке часто перевершує «середні» dedup-коефіцієнти в реальному житті.
Рішення: якщо стиснення дає помітну економію, це ваш дефолтний важіль для місця. Залишайте dedup для вузьких, валідаційних випадків.
Завдання 8: Побачити, чи існує special vdev (прискорення метаданих) і чи він розмірено адекватно
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
special ONLINE 0 0 0
mirror-1 ONLINE 0 0 0
nvme0n1p2 ONLINE 0 0 0
nvme1n1p2 ONLINE 0 0 0
errors: No known data errors
Що це означає: існує special vdev mirror. Метадані (і потенційно малі блоки) можуть потрапляти туди, знижуючи затримки пошуків DDT при промахах ARC.
Рішення: якщо ви взагалі використовуєте dedup, special vdev може допомогти. Але ставтеся до special vdev як до tier-0: якщо ви його втратите без редундансу, можна втратити пул.
Завдання 9: Перевірити, куди йдуть метадані (політика 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, не малі блоки файлів. DDT — «метаданоподібний», тому може виграти навіть за значення 0.
Рішення: не ставте special_small_blocks без розуміння ємності і домену відмов. Це може перемістити велику частину даних на special vdev.
Завдання 10: Перевірити поведінку txg sync (коли система «зависає»)
cr0x@server:~$ cat /proc/spl/kstat/zfs/txg | head
0 0 0x01 7 448 13056000 2112000
# txgs synced txg ...
Що це означає: статистика txg залежить від версії; суть у тому, щоб корелювати «зависання» з каденцією sync. Дедуп-індуковані випадкові читання можуть продовжити роботу sync і блокувати прогрес.
Рішення: якщо інтервали sync роздуваються під навантаженням записів, підозрюйте метадані і промахи DDT; потім підтвердіть iostat-затримкою і тиском ARC.
Завдання 11: Доведіть, що датасет зараз платить податок dedup (спостерігайте затримку запису через fio)
cr0x@server:~$ fio --name=randwrite --filename=/tank/vm/testfile --direct=1 --rw=randwrite --bs=16k --iodepth=16 --numjobs=1 --size=2g --runtime=30 --time_based --group_reporting
randwrite: (g=0): rw=randwrite, bs=(R) 16.0KiB-16.0KiB, (W) 16.0KiB-16.0KiB, (T) 16.0KiB-16.0KiB, ioengine=psync, iodepth=16
fio-3.33
...
write: IOPS=850, BW=13.3MiB/s (14.0MB/s)(400MiB/30001msec)
slat (usec): min=7, max=300, avg=18.5, stdev=6.2
clat (msec): min=2, max=180, avg=18.9, stdev=22.1
lat (msec): min=2, max=180, avg=18.9, stdev=22.1
Що це означає: висока хвостова затримка (clat max 180ms) типова, коли пошуки метаданих йдуть на повільні диски, навіть якщо середнє виглядає «нормально».
Рішення: якщо хвостова затримка огидна і корелює з дедуп-важкими навантаженнями, припиняйте намагання «оптимізувати додаток». Виправляйте шлях зберігання або приберіть dedup.
Завдання 12: Перевірити дрейф властивості dedup (хтось увімкнув «тимчасово»)
cr0x@server:~$ zfs get -r -s local,inherited -o name,property,value,source dedup tank | head
NAME PROPERTY VALUE SOURCE
tank/vm dedup on local
tank/vm/old dedup on inherited from tank/vm
tank/vm/tmp dedup on inherited from tank/vm
Що це означає: dedup поширюється через наслідування, що і є тим, як «експеримент на одному датасеті» стає «весь пул тепер платить податок пошуку».
Рішення: розірвіть наслідування там, де воно не потрібно. Dedup має бути опцією «за бажанням», а не фонова властивість.
Завдання 13: Вимкнути dedup для нових записів (без дурної надії, що це виправить існуючі дані)
cr0x@server:~$ sudo zfs set dedup=off tank/vm
Що це означає: нові блоки не дедуплюватимуться, але старі блоки залишаються дедуплікованими і все ще залежать від DDT для читань.
Рішення: зробіть це як раннє стримання шкоди, а потім сплануйте реальний фікс: перезапис даних на ціль без dedup.
Завдання 14: Оцінити «наскільки поганим може бути перезапис?» за допомогою used і logicalused
cr0x@server:~$ zfs get -o name,property,value used,logicalused,referenced,logicalreferenced tank/vm
NAME PROPERTY VALUE
tank/vm used 8.50T
tank/vm logicalused 11.2T
tank/vm referenced 8.50T
tank/vm logicalreferenced 11.2T
Що це означає: логічні дані більші за фізичні. Якщо ви перезапишете без dedup, вам потрібен простір для фізичного розширення (або більша ціль).
Рішення: плануйте ємність перед міграцією з dedup. Багато «ми просто скопіюємо» планів провалюються, коли фізичне використання стрибає.
Завдання 15: Безпечна міграція через send/receive (нудний інструмент, що працює)
cr0x@server:~$ sudo zfs snapshot -r tank/vm@move-001
cr0x@server:~$ sudo zfs send -R tank/vm@move-001 | sudo zfs receive -u tank_nodedup/vm
Що це означає: ви створили консистентну копію. Якщо на цілі встановлено dedup=off, нові блоки запишуться без dedup.
Рішення: це чистий вихідний зʼїзд. Використовуйте -u, щоб отримати unmounted, перевірте, потім акуратно переключіться.
Три корпоративні міні-історії з польових робіт
1) Інцидент через хибне припущення: «Dedup — на рівні датасету, тож він не може нашкодити пулу»
Середня компанія мала кластер віртуалізації на ZFS. Команда зберігання увімкнула dedup на датасеті для шаблонних VM, очікуючи великої економії.
Припущення заспокоювало: це лише один датасет; в гіршому випадку це сповільнить лише цей датасет.
За два тижні служба підтримки почала отримувати тікети про «випадкову повільність». Завантаження VM іноді зависало. Нічні вікна бекапів розширювалися і пропускали SLA.
Початкова реакція була передбачувана: додати більше шпинделів у RAIDZ, підлаштувати кешгіпервізора, звинуватити мережу, потім «голосних сусідів».
Поворотною точкою стало помічання зростання read IOPS під час інтенсивних записів. Це не нормально. Стало очевидно, що пошуки DDT промахуються по кешу і примушують випадкові читання по всьому пулу.
Хоч dedup був увімкнений на рівні датасету, DDT жив у пулі і шлях I/O впливав на всіх, хто використовував ті самі vdev.
Виправлення не було героїчним. Вони негайно вимкнули dedup для нових записів, а тоді поетапно перенесли дані через send/receive на пул без dedup у вихідні.
Продуктивність стабілізувалася ще до завершення міграції, бо активний робочий набір перемістився першим і тиск на DDT зменшився.
Постмортем вивід був простим: у спільному сховищі «функції на рівні датасету» все одно мають наслідки на рівні пулу. Якщо гарячий шлях фічі торкається метаданих пулу,
трактуйте це як зміну на рівні пулу, а не експеримент на датасеті.
2) Оптимізація, що обернулася проти: «увімкнемо dedup для бекапів, там здебільшого дублікати»
Інша команда мала ціль бекапів на ZFS і прагнула зменшити зростання ємності. Хтось подивився на бекапи, побачив повтори і зробив обґрунтовану ставку:
dedup повинен перемолоти повторювані повні бекапи. Середовища мали багато CPU і «достатньо RAM», а диски були сумішшю HDD і невеликого SSD для кеша.
Місяць усе виглядало як успіх. dedupratio зростав. Покупки сховища відкладалися. Потім розширили зберігання за часом. DDT виріс. ARC — ні. Відновлення сповільнилося. Тестові відновлення стали неприємними.
День інциденту настав, коли великий restore запустили одночасно з інгестом бекапів. Затримки підскочили по всьому пулу. Моніторинг показував, що диски завантажені, але пропускна спроможність низька.
Класична насиченість випадкових I/O. Зросли читання метаданих, бо активний робочий набір DDT більше не вміщувався в памʼять.
Команда думала, що оптимізує ємність; насправді вони перетворили кожен запис на операцію з посиленими читаннями в найгірший момент.
Виправлення було контринтуїтивним: вони зупинили dedup, активніше використали стиснення і змінили pipeline бекапів, щоб уникнути запису ідентичних даних (кращі інкрементальні ланцюги, інше нарізання, інтелектуальніші політики копіювання).
Урок: dedup може виглядати відмінно на початку, а потім звалитися круто, коли таблиця перетне поріг кешу. Падіння — не поступове. Це функція стрибка.
3) Сумно, але правильна практика, що врятувала день: «виміряйте DDT перед включенням»
Команда фінансових послуг мала запит: зберігати кілька версій образів VM з мінімальним ростом. Бізнес попросив dedup. Команда зберігання відповіла «можливо»,
що є ввічливою формою «ми виміряємо перед тим, як пожалкуємо».
Вони виділили невеликий тестовий пул, що відтворює типи vdev продакшну, і прогнали репрезентативний інгест: кілька сотень гігабайт реального churn образів VM.
Збирали zdb -DD гістограми, дивилися поведінку ARC і вимірювали затримки під паралельним навантаженням. Повторили тест з тільки стисненням і з різними recordsize/volblocksize.
Нічого особливого — просто дисципліна.
Результат був нудно найкращий. Dedup зекономив менше, ніж очікували, бо дані частково вже були стиснуті і зміни були розкидані.
Стиснення само по собі дало більшість економії з стабільною продуктивністю. Оцінки робочого набору DDT показали, що їм знадобиться більше RAM, ніж платформа може надати без оновлення.
Вони відмовилися від dedup у продакшні та задокументували причини. Через півроку новий керівник знову піднімав питання. Команда відкрила звіт, прогнала менший валідаційний тест на актуальних даних і знову уникла самосотвореного інциденту.
Висновок: найцінніша оптимізація — та, від якої ви вирішили утриматися після вимірювань.
Жарт №2: DDT — це таблиця, що ніколи не перестає рости, тільки вона на вашому критичному шляху і не приймає «приховати колонку» як фікс продуктивності.
Поширені помилки: симптоми → корінь → виправлення
1) Записи повільні, але диски показують багато читань
Симптоми: робочі задачі, орієнтовані на запис, викликають read IOPS, високий r_await і імпульсні затримки.
Корінь: пошуки DDT промахуються в ARC; записи DDT читаються з диска випадково під час записів.
Виправлення: збільшити RAM/ARC, перемістити метадані на швидші пристрої (special vdev) або мігрувати з dedup. Якщо ви не можете тримати робочий набір DDT у гарячому кеші, dedup — невдалий вибір.
2) «Ми вимкнули dedup, але все ще повільно»
Симптоми: властивість dedup вимкнена, але пул усе ще поводиться як метаданно-важкий і непередбачуваний.
Корінь: існуючі блоки залишилися дедуплікованими; читання все ще залежать від DDT і його кеш-поведінки.
Виправлення: перезапишіть дані на ціль без dedup (send/receive), потім виведіть дедупльовану копію з експлуатації.
3) Пул нормально працює, поки не перестає; потім усе падає
Симптоми: місяці нормальної продуктивності, потім раптові стрибки, таймаути, довгий txg sync і непередбачувана поведінка додатків.
Корінь: DDT перетнув поріг робочого набору ARC; частота промахів зросла і вибухнули випадкові читання.
Виправлення: трактуйте це як провал планування ємності: ріст DDT має бути запланований як будь-яка інша ємність. Додайте RAM/швидкі метадані або вийдіть з dedup.
4) Перезавантаження триває вічно, імпорт крихкий
Симптоми: повільний імпорт пулу, система ніби зависає після перезавантаження під навантаженням.
Корінь: величезні набори метаданих (включно з DDT), що взаємодіють з обмеженим кешем; система повинна «підігріти» робочий набір, одночасно обслуговуючи I/O.
Виправлення: зменшіть розмір dedup через міграцію; забезпечте адекватний RAM; уникайте змішування важкого продакшн-навантаження з холодним кеш-імпортом, якщо можна контролювати послідовність.
5) Додали special vdev, але продуктивність не покращилась
Симптоми: ви встановили швидкі SSD як special vdev, але біль від dedup лишився.
Корінь: робочий набір DDT все ще занадто великий; або special vdev перевантажений/занадто малий; або ви чекали, що це виправить навантаження, обмежене CPU (checksum/compress).
Виправлення: підтвердіть розподіл метаданих і затримки пристроїв. Розмірьте special vdev правильно, зробіть mirror і все одно плануйте RAM. Special vdev — прискорювач, а не диво.
6) Dedup увімкнено в датасеті, що вже містить стиснуті/зашифровані блоки
Симптоми: незначне покращення dedupratio, але помітне зниження продуктивності.
Корінь: можливості dedup обмежені, коли дані вже високої ентропії (стиснуті, зашифровані або унікальні за конструкцією).
Виправлення: тримайте dedup вимкненим. Використовуйте стиснення, розумні стратегії бекапу або дедуп на рівні додатку/чейкінг, якщо потрібно.
7) Dedup увімкнено на загальних файлових шарах «бо може допомогти»
Симптоми: періодична повільність на змішаних навантаженнях; звʼязок незрозумілий.
Корінь: податок dedup застосовано до широких, непередбачуваних патернів даних; DDT churn з поганою локальністю.
Виправлення: обмежте dedup вузькими датасетами, де дублювання доведено і стабільне. Інакше вимкніть і мігруйте.
Чеклісти / покроковий план
Чекліст для рішення: чи увімкнути взагалі dedup?
- Виміряйте дублювання на реальних даних: не вгадуйте. Якщо не можете протестувати — дефолт до «ні».
- Оцініть розмір DDT і робочий набір: використовуйте
zdb -DDна тестовому пулі або зразку; припускайте ріст з ретеншеном. - Бюджетуйте RAM з запасом: вам потрібен ARC і для звичайних читань. Якщо dedup задушить усе інше — це неприйнятно.
- Перевірте затримки під навантаженням конкурентності: тестуйте реалістичними паралельними записами і читаннями, а не однопотоковим бенчмарком.
- Заздалегідь визначте план виходу: якщо піде не так, як ви перезаписуєте дані і куди вміститься додаткове фізичне використання?
Операційний чекліст: у вас уже є dedup і він шкодить
- Зупиніть кровотечу: встановіть
dedup=offдля нових записів на уражених датасетах. - Квантируйте радіус ураження: збирайте
zpool get dedupratio,zdb -DD, ARC-статистику і iostat-затримки. - Визначте активні «гарячі» датасети: звідки йдуть записи і читання під час інцидентів?
- Обирайте ремедію: додайте RAM, прискоріть метадані (special vdev) або мігруйте з dedup. Не намагайтеся «налаштуваннями» вирішити фундаментально завеликий DDT.
- Плануйте міграційну ємність: порівняйте
logicalusedіused. Переконайтеся, що ціль вмістить розширене фізичне використання. - Виконуйте з snapshots і send/receive: тримайте процес нудним, перевірним і відновлюваним.
- Переключайте акуратно: отримайте unmounted, перевірте, потім змініть точки монтування чи споживачів.
- Після переключення: видаляйте старі дедупліковані датасети тільки коли впевнені; перевіряйте, що DDT поступово зменшується в міру звільнення блоків.
Профілактичний чекліст: не дати dedup поширитися непомітно
- Аудит властивості dedup за наслідуванням щомісяця на продуктивних пулах.
- Вимагаєте запису зміни перед увімкненням dedup будь-де.
- Налаштуйте алерти на зміни dedupratio і незвичні read IOPS під час вікон записів.
- Тримайте «зони без dedup» для загальних навантажень; робіть датасети з dedup явними і рідкісними.
FAQ
Чи «поганий» ZFS dedup?
Ні. Він просто дорогий. Він чудово працює, коли дублювання високе, стабільне і ви можете тримати робочий набір DDT гарячим (RAM і/або швидкі метадані).
Це пастка, коли ви вмикаєте його надією.
Чому dedup так сильно сповільнює записи?
Тому що він додає пошук на шлях запису. Якщо запис DDT не в ARC, ZFS виконує додаткові випадкові читання, щоб знайти його, перш ніж вирішити, писати чи ні.
Чи можу я вимкнути dedup і одразу повернути продуктивність?
Ви можете зупинити дедуплікацію нових записів, встановивши dedup=off. Але існуючі дедупліковані блоки залишаються і все ще залежать від DDT для читань.
Реальне відновлення зазвичай вимагає перезапису/міграції даних.
Як дізнатися, чи DDT вміщується в RAM?
Оцініть через zdb -DD (гістограми і «in core» розміри) і потім валідуйте поведінку: якщо періоди записів викликають випадкові читання і стрибки затримки,
ймовірно, ви промахуєтеся. «Вміщення» — це про робочий набір, а не про загальний розмір.
Чи знижує стиснення ефективність dedup?
Часто так, бо стиснення змінює он-диск подання і дані високої ентропії після стиснення мають менше ідентичних блоків.
Практично, якщо стиснення вже дає хорошу економію, dedup може бути не вартий витрат.
Чи підходить dedup для образів VM?
Іноді. Golden images і багато клонів можуть добре дедуплюватися, але VM-навантаження також чутливі до затримок і генерують випадкові записи.
Якщо ви не можете гарантувати локальність DDT і швидкі метадані, ви можете перетворити «зекономлене місце» на «борг по продуктивності».
Чи можна помістити DDT на SSD?
Через special vdev ви можете спрямувати алокації метаданих на швидкі пристрої, що може включати структури типу DDT. Це знижує біль при промахах кеша.
Але це підвищує залежність від цих пристроїв; вони мають бути надлишковими і правильно розмірені.
Чи додавання дисків виправить продуктивність dedup?
Може допомогти, якщо вузьке місце — випадкові read IOPS і ви на HDD, але зазвичай це неефективне рішення порівняно з додаванням RAM або переміщенням метаданих на швидке сховище.
Якщо DDT не вміщується, більше шпинделів може трохи полегшити треш, але не вирішить корінь проблеми.
Який найбезпечніший спосіб «undedup» датасету?
Зробіть snapshot і zfs send | zfs receive до цільового датасету з dedup=off. Перевірте, потім переключіться.
Це перезапише блоки і зніме залежність даних від DDT.
Чи є правило великого пальця щодо RAM на TB для dedup?
Правила великого пальця існують, бо людям потрібно було щось говорити на нарадах. Реальна відповідь залежить від розподілу розмірів блоків, патернів дублювання
і вашого активного робочого набору. Якщо ви не можете виміряти — припускайте, що це буде більше, ніж вам хотілося б.
Висновок: кроки, що не зіпсують вихідні
Dedup ZFS не злий. Він просто чесний. Він змушує вас платити наперед — у RAM, у I/O метаданих і в операційній складності — щоб ви могли зекономити місце потім.
Якщо ви не готові платити постійно, DDT збере проценти у вигляді затримок.
Практичні наступні кроки:
- Аудит: запустіть рекурсивний
zfs get dedupі знайдіть, де dedup увімкнено і наслідкове. - Квантифікація: збережіть вивід
zdb -DDіzpool get dedupratioдля пула. - Кореляція: використайте
iostat -xпід час повільних вікон; шукайте read IOPS і високий read await під час записів. - Контейнмент: встановіть
dedup=offдля нових записів там, де це не критично. - Вибір: або профінансуйте dedup належно (RAM + швидкі метадані + валідація), або мігруйте з ним через send/receive і поверніть передбачуваність.
Якщо запамʼятаєте лише одну річ: успіх dedup — це не «скільки місця ми зекономили?» Це «чи можемо ми все ще досягати цільових затримок, коли DDT має поганий день?»