Ви запускаєте scrub тому, що відповідаєте за систему. ZFS робить те, що ви попросили, бо воно слухняне.
А потім приходить понеділок вранці і ваш приємний стабільний графік латентності перетворюється на гребінь: зависання сховища віртуальних машин,
запити бази даних тягнуться, і хтось серйозно каже «мережна проблема».
Scrub нічого не «зламав». Він лише голосно показав, наскільки тонкі у вас запасні шкали продуктивності
і наскільки слабо ви контролюєте фоновий I/O. Це інструкція для запуску scrub в продакшні,
щоб не перетворювати ваші найактивніші години на полігон для помилок.
Що насправді робить scrub (і чому це болить)
ZFS scrub проходить по пулу і перевіряє цілісність даних, читаючи блоки та перевіряючи контрольні суми.
Якщо є надлишковість і ZFS виявляє пошкоджений блок, він відновлює його, читаючи хорошу копію і перезаписуючи
погану. Scrub — це не «сканування файлової системи» в старому сенсі; це систематичний аудит збережених даних.
Цей аудит має ціну: тривалі читання, деякі записи і сильний тиск на черги пристроїв.
Біль виникає через конкуренцію. Ваше продакшн-навантаження хоче низької латентності для випадкових I/O.
Scrub хоче високої пропускної здатності та напівпослідовних читань (але не ідеально послідовних — метаспейси, фрагментація і
розмір запису ускладнюють картину). Обидва потрапляють на ті самі vdev-и, ділять одні й ті самі черги і змагаються за
запас потужності. Якщо у вас HDD, очікуйте, що scrub підніме середній час пошуку до світлого дня. Якщо SSD — scrub все одно може
з’їсти бюджет IOPS і пропускну здатність контролера, а також посилити проблеми з garbage collection.
Ще один момент: scrub конкурує з resilver, і resilver не є опціональним. Scrub — це планова операція;
resilver — це «швидка допомога». Якщо ви плануєте scrubs так агресивно, що resilver-и постійно «повільні але стабільні»,
ви розширюєте вікно ризику. Повільний resilver — це не просто дратівливість.
Це час, протягом якого ви відкриті для другої відмови.
«Але ZFS — copy-on-write, тому це не повинно сильно заважати.» Це заспокійливе речення, а не план.
CoW змінює поведінку записів і семантику узгодженості; воно не дає вам нескінченних I/O-полос.
Жарт №1: scrub у пікові години — як пилососити під час Zoom-дзвінка — технічно корисно, соціально катастрофічно.
Scrub vs. resilver vs. SMART long tests
Ці три часто зводять до «обслуговування» і тоді планують, як візит до стоматолога.
Вони не взаємозамінні:
- Scrub: Проходить пул, перевіряє контрольні суми; відновлює приховані корупції за допомогою надлишковості.
- Resilver: Відтворює дані на замінений пристрій; пріоритет — безпека даних, не зручність.
- SMART long test: Самотестування пристрою; може виявити проблеми диска, але не перевіряє надлишковість або контрольні суми ZFS.
Здорова продакшн-позиція використовує всі три, але ніколи не прикидається, що один замінює інший. Scrub каже, чи дані читабельні та коректні.
SMART каже, чи диск «чесний» сьогодні. Resilver каже, наскільки швидко можна перестати хвилюватися після заміни диска.
Факти та історія, які варто знати
Це не цікаві факти для вікторини. Вони змінюють, як ви плануєте і як інтерпретуєте результати.
- Scrubs існують тому, що прихована корупція реальна. «Bit rot» — це не міф; контрольні суми end-to-end в ZFS були створені для її виявлення.
- ZFS зробив контрольні суми стандартом у загального призначення сховищ. Коли ZFS з’явився в Sun (середина 2000-х), end-to-end цілісність не була стандартом у звичайних файлових системах.
- Scrub — це операція на пулі, а не на датасеті. Ви не можете проскрубити лише «важливий датасет» і назвати це покриттям.
- Scrub-чтення іноді перетворюються на записи. Якщо ZFS знаходить погані дані і може їх відновити, він перезапише виправлені блоки.
- Характеристики відбудови RAIDZ відрізняються від дзеркал. Дзеркала часто ремонтують дані з прямої копії; RAIDZ потребує обчислення парності і може поводитися інакше під навантаженням.
- Великі пули роблять «щомісячний scrub» брехнею. Якщо scrub триває 10 днів, «щомісяця» насправді означає «завжди». Це помилка планування, а не календарна проблема.
- Scrub конкурує з ARC і поведінкою prefetch. Кеш може допомогти або зашкодити залежно від тиску пам’яті і навантаження; scrubs можуть витісняти «гарячі» дані додатка.
- Розкладка vdev визначає поведінку scrub. Додавання vdev-ів додає паралелізм; додавання більших дисків збільшує тривалість. «Той самий розмір пулу» не означає «той самий час scrub».
- Деякі уповільнення scrub — це побічний ефект write amplification. Інтенсивні записи під час scrub можуть посилювати фрагментацію і робити наступні scrubs повільнішими.
Парафразуючи John Allspaw: «Надійність приходить від проєктування на випадок відмов, а не від прикидання, що їх не буде.»
Scrubs — один з інструментів, який тримає відмови чесними. Планування — це спосіб не дозволити інструменту нашкодити вам.
Вибір політики scrub: частота, вікна та очікування
Частота: перестаньте копіювати «щомісяця» з інтернету
«Scrub щомісяця» — добрий дефолт для багатьох пулів і жахливе правило для інших. Частота має базуватися на:
(1) наскільки швидко ви можете виконати scrub, (2) як швидко ви хочете виявляти приховану корупцію, і (3) скільки ризику ви
приймаєте, запускаючи scrubs під навантаженням.
Практичні поради, які працюють у продакшні:
- HDD RAIDZ, великі ємності: щомісяця може бути нормально, якщо scrubs завершуються за день-два. Якщо ні — розгляньте інтервал 6–8 тижнів і інвестуйте в скорочення тривалості scrub (більше vdev-ів, краща розкладка), замість перетворення пулу на постійну фонову задачу.
- HDD дзеркала для чутливих до латентності навантажень: кожні 2–4 тижні часто реалістично, бо дзеркала скрабляться швидше і команда частіше хоче швидкого виявлення.
- Повністю flash-пули: частота може бути більшою, але не робіть цього «бо SSD швидкі». Контролери насичуються, і ваші пікові години все ще важливі.
- Архівні пули з низькою зміною даних: можна рідше, але лише якщо ви готові терпіти довший час виявлення прихованої корупції.
Вікна: обирайте час по спостереженнях, а не по припущеннях
Найкраще вікно для scrub — це те, яке ваші користувачі не помічають. Це не завжди «2:00 неділі». У глобальних компаніях
неділя 2:00 — це понеділок 10:00 десь. У компаніях з пакетною обробкою ночі можуть бути завантаженішими за дні. У бекап-важких системах
вихідні — це теж свої «години війни».
Ви обираєте вікно так само, як вікно технічного обслуговування для бази даних: вимірюючи час відгуку при читанні,
глибину черги і CPU steal, потім обираючи найменш поганий період. Якщо у вас слабка телеметрія, почніть з:
(a) години з найменшим 95-м перцентилем дискової латентності, (b) години з найменшим синхронним записовим навантаженням,
(c) години, найменш ймовірної для запуску бекапів.
Встановлення очікувань: визначте «допустимий біль»
Якщо ви не визначите допустимий вплив, scrub визначить його за вас. Пропишіть числа:
- Максимально допустиме збільшення читальної латентності (наприклад, +3 ms на p95 для HDD, +0.5 ms для SSD).
- Максимально допустиме зниження IOPS (наприклад, не нижче 70% від бази для критичних пулів).
- Умови для скасування (наприклад, відмінити scrub, якщо латентність пулу перевищує поріг протягом 15 хвилин).
Це важливо, бо ZFS охоче буде виконувати scrub поки не скажете інакше.
Моніторинг, який справді прогнозує проблеми
«Scrub повільний» — це не метрика. Scrub — це робоче навантаження. Вам потрібні ті самі сигнали, які ви б хотіли для будь-якого навантаження:
пропускна здатність, латентність, конкуренція та насичення. І вам потрібен контекст специфічний для ZFS: стан vdev-ів,
помилки контрольних сум і чи пул зараз ремонтує дані.
Що спостерігати під час scrub
- Швидкість сканування пулу і ETA з
zpool status. - Використання на рівні vdev (глибина черги, await, svctm де застосовно) через
iostatабоzpool iostat. - Латентність додатків (p95/p99 бази даних, латентність сховища віртуальних машин).
- Поведінка ARC: зміни співвідношення попадань у кеш і тиск пам’яті можуть перетворити scrub на хвилю витіснення кешу.
- Лічильники помилок: помилки читання/запису/контрольних сум, а також підказки SMART.
Пастка: спостерігати лише пропускну здатність. Високі МБ/с можуть все одно означати жахливу латентність для малих синхронних I/O.
Ваші користувачі не відчувають МБ/с; вони чекають.
План швидкої діагностики
Коли хтось каже «усе повільно» і ви підозрюєте scrub, вам потрібен трьоххвилинний шлях до правдоподібної відповіді.
Це порядок, який я використовую в продакшні, бо він швидко збігається до висновку.
Перше: підтвердьте scrub/resilver і чи відбувається ремонт
- Перевірте, чи запущений scrub і його швидкість сканування.
- Перевірте, чи знаходить він помилки (ремонт збільшує навантаження запису).
- Перевірте, чи триває resilver (це змінює пріоритети).
Друге: визначте насичений ресурс (диск, CPU або щось, що видає себе за диск)
- Якщо диски показують високий await/глибину черги і низьке idle — ви обмежені I/O.
- Якщо CPU зашитий у kernel-потоках (або домінує iowait) — система не встигає підживлювати I/O.
- Якщо задіяні мережеві шляхи сховища (iSCSI/NFS), переконайтеся, що ви не дебажите не той шар.
Третє: знайдіть найгірший vdev
Продуктивність ZFS формується найповільнішим vdev-ом, коли потрібен рівномірний прогрес. Один поганий диск може
затягнути час scrub і підвищити час під ризиком. Використовуйте статистику по vdev і лічильники помилок; не гадьте.
Четверте: вирішіть «тротлити, перемістити або скасувати»
- Притиснути (throttle), якщо пул здоровий і потрібно лише зменшити вплив.
- Перенести вікно, якщо це передбачуваний конфлікт з пакетними роботами/бекапами.
- Скасувати, якщо латентність шкодить користувачам і ви можете безпечно відновити пізніше.
- Не скасовуйте resilver, якщо ви не зовсім розумієте, чим ризикуєте.
Практичні завдання: команди, виходи та рішення
Ось реальні команди, які ви можете виконати. Кожне завдання містить: команду, що означає вихід, і рішення.
Я припускаю типовий OpenZFS на Linux або FreeBSD. Деякі параметри відрізняються за платформою; логіка діагностики не змінюється.
Завдання 1: Підтвердити, чи запущено scrub і наскільки він просунутий
cr0x@server:~$ zpool status tank
pool: tank
state: ONLINE
scan: scrub in progress since Mon Dec 23 01:10:12 2025
3.12T scanned at 612M/s, 1.74T issued at 341M/s, 21.4T total
0B repaired, 8.12% done, 17:21:33 to go
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
errors: No known data errors
Значення: Scrub активний, швидкості scanned та issued відрізняються (деякі читання в черзі, але ще не відправлені),
ETA довгий. Немає ремонтів. Помилок немає.
Рішення: Якщо це накладається на пікові години — тротльте або перенесіть, а не панікуйте. Якщо ETA абсурдна,
підозрівайте вузьке місце vdev або суперництво з іншим навантаженням.
Завдання 2: Отримати швидкості I/O по vdev, щоб помітити відстаючий
cr0x@server:~$ zpool iostat -v tank 5 3
capacity operations bandwidth
pool alloc free read write read write
-------------------------- ----- ----- ----- ----- ----- -----
tank 10.2T 11.2T 3.10K 210 320M 22.1M
raidz2-0 10.2T 11.2T 3.10K 210 320M 22.1M
sda - - 520 35 54.1M 3.7M
sdb - - 515 34 53.8M 3.6M
sdc - - 518 36 54.0M 3.8M
sdd - - 110 33 11.2M 3.6M
sde - - 521 35 54.3M 3.7M
sdf - - 516 37 54.0M 3.8M
-------------------------- ----- ----- ----- ----- ----- -----
Значення: Один диск (sdd) читає значно менше за сусідів. Це той, хто краде час scrub.
Рішення: Витягніть SMART-статус і логи помилок для sdd. Якщо він повільний, але без явних помилок, він все одно може деградувати
(таймаути, відкладені перерозподілені сектора або проблеми з прошивкою). Розгляньте проактивну заміну.
Завдання 3: Перевірити лічильники помилок пристрою і чи ZFS «мовчки» не перезавантажує спроби
cr0x@server:~$ zpool status -v tank
pool: tank
state: ONLINE
scan: scrub in progress since Mon Dec 23 01:10:12 2025
3.30T scanned at 585M/s, 1.92T issued at 340M/s, 21.4T total
0B repaired, 8.95% done, 16:58:01 to go
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 2 0 0
sde ONLINE 0 0 0
sdf ONLINE 0 0 0
errors: No known data errors
Значення: sdd має лічені помилки читання. Навіть якщо ZFS прозоро відремонтував, це сигнал.
Рішення: Розглядайте це як подію апаратури. Не чекайте, поки «стан погіршиться». Плануйте заміну
і стежте за ескалацією лічильників під час scrub.
Завдання 4: На Linux перевірте імена udev та правильно зіставте диски перед заміною
cr0x@server:~$ ls -l /dev/disk/by-id/ | grep -E 'sdd$'
lrwxrwxrwx 1 root root 9 Dec 26 10:02 ata-WDC_WD120EDAZ-11F3RA0_9GJ3K2AA -> ../../sdd
lrwxrwxrwx 1 root root 10 Dec 26 10:02 wwn-0x50014ee2b6d12345 -> ../../sdd
Значення: У вас є стабільні ідентифікатори для sdd. Добре. Перестаньте використовувати /dev/sdX у процедурах заміни,
якщо любите спати спокійно.
Рішення: Використовуйте шлях by-id у zpool replace і в документації для on-call.
Завдання 5: Перевірити, чи латентність додатків корелює зі scrub
cr0x@server:~$ iostat -x 5 2
Linux 6.8.0 (server) 12/26/2025 _x86_64_ (32 CPU)
avg-cpu: %user %nice %system %iowait %steal %idle
6.30 0.00 3.10 18.40 0.00 72.20
Device r/s w/s rMB/s wMB/s rrqm/s wrqm/s %util await
sda 92.0 6.0 9.6 0.7 0.0 0.3 74.0 14.8
sdb 91.5 6.1 9.6 0.7 0.0 0.2 73.1 15.2
sdc 92.2 6.0 9.6 0.7 0.0 0.2 73.9 15.0
sdd 19.3 5.9 2.1 0.7 0.0 0.1 99.0 87.4
sde 91.8 6.0 9.6 0.7 0.0 0.2 74.2 14.9
sdf 91.6 6.2 9.6 0.7 0.0 0.2 73.5 15.1
Значення: sdd завантажений на 99% з великим await. Інші — відносно в порядку. iowait підвищений.
Це класична ситуація «один диск псує вечірку».
Рішення: Тротлінг scrub може зменшити біль, але не виправить sdd. Пріоритет — триаж здоров’я пристрою.
Завдання 6: Перевірити, чи пул обмежений одним vdev або загальною пропускною здатністю
cr0x@server:~$ zpool iostat tank 1 5
capacity operations bandwidth
pool alloc free read write read write
---------- ----- ----- ----- ----- ----- -----
tank 10.2T 11.2T 3.05K 230 318M 24.0M
tank 10.2T 11.2T 3.12K 240 326M 25.0M
tank 10.2T 11.2T 2.98K 225 310M 23.1M
tank 10.2T 11.2T 1.40K 980 145M 96.2M
tank 10.2T 11.2T 3.10K 235 320M 24.3M
Значення: В одному інтервалі видно сплеск записів; ймовірно, додаткові записи додатка конфліктують зі scrub.
Рішення: Якщо інтенсивні записові задачі накладаються (бекапи, компакти, ротація логів), перенесіть вікно scrub
або тротльте scrub, щоб захистити латентність.
Завдання 7: Перевірити, чи тиск на ARC викликає побічні проблеми
cr0x@server:~$ arcstat 5 3
time read miss miss% dmis dm% pmis pm% mmis mm% size c
10:14:05 812K 124K 15 108K 87% 10K 8% 6K 5% 96.0G 110G
10:14:10 790K 210K 27 198K 94% 8K 4% 4K 2% 96.0G 110G
10:14:15 820K 260K 32 250K 96% 7K 3% 3K 1% 96.0G 110G
Значення: Частка промахів збільшується під час scrub; домінують demand misses. Scrub, ймовірно, витісняє гарячі дані.
Рішення: Якщо ваше навантаження чутливе до кешу, тротльте scrub, плануйте його на час низького оберту кешу
і перевірте, чи ARC налаштований на пікові вимоги.
Завдання 8: Перевірити журнали подій ZFS навколо початку проблем
cr0x@server:~$ zpool events -v | tail -n 12
TIME CLASS
Dec 26 2025 10:02:11.123456789 ereport.fs.zfs.io
pool = tank
vdev_path = /dev/disk/by-id/wwn-0x50014ee2b6d12345
vdev_guid = 1234567890123456789
errno = 5
io_priority = scrub
Dec 26 2025 10:02:14.987654321 ereport.fs.zfs.io
pool = tank
vdev_path = /dev/disk/by-id/wwn-0x50014ee2b6d12345
errno = 5
io_priority = scrub
Значення: I/O помилки на певному vdev під час scrub. errno 5 — помилка вводу-виводу.
Рішення: Перестаньте сперечатися про планування і почніть планувати заміну. Scrub виконує свою роботу, знаходячи слабкі ланки.
Завдання 9: Перевірити історію scrub і чи вони регулярно завершуються
cr0x@server:~$ zpool status tank | sed -n '1,20p'
pool: tank
state: ONLINE
scan: scrub in progress since Mon Dec 23 01:10:12 2025
3.45T scanned at 610M/s, 2.05T issued at 362M/s, 21.4T total
0B repaired, 9.30% done, 16:21:02 to go
Значення: Ви отримуєте поточний прогрес scrub, але для історичної інформації слід логувати зовні
або опитувати платформні інструменти. Багато команд помічають, що scrubs «тривають вічно» лише після року мовчазних проблем.
Рішення: Почніть записувати старт/фініш/кількість відремонтованих байтів у моніторинг. Якщо scrubs не завершуються між вікнами,
змініть частоту або архітектуру пулу.
Завдання 10: Запустити scrub навмисно (і зрозуміти, що означає «запустити»)
cr0x@server:~$ sudo zpool scrub tank
cr0x@server:~$ zpool status tank | head -n 8
pool: tank
state: ONLINE
scan: scrub in progress since Thu Dec 26 10:20:55 2025
0B scanned at 0B/s, 0B issued at 0B/s, 21.4T total
0B repaired, 0.00% done, no estimated completion time
Значення: Scrub поставлено в чергу і запущено; початкові швидкості можуть показувати 0 до розгону і оновлення статистики.
Рішення: Якщо тестуєте планування, запускайте scrubs вручну у контрольованому вікні, а потім вимірюйте вплив.
Завдання 11: Призупинити/зупинити scrub, коли потрібно (і прийняти компроміс)
cr0x@server:~$ sudo zpool scrub -s tank
cr0x@server:~$ zpool status tank | head -n 8
pool: tank
state: ONLINE
scan: scrub canceled on Thu Dec 26 10:27:12 2025
3.62T scanned at 600M/s, 2.11T issued at 350M/s, 21.4T total
0B repaired, 9.86% done
Значення: Scrub скасовано; він не «продовжить звідти, де зупинився» як безперервний процес. Наступний scrub ресканує.
Рішення: Скасовуйте лише коли вплив на клієнтів вимагає цього. Потім перенесіть новий scrub у безпечніше вікно найближчим часом.
Якщо ви скасували через невдалий диск — заміна має бути пріоритетом.
Завдання 12: На Linux перевірити і встановити параметри модуля, пов’язані зі scrub (приклад: delay)
cr0x@server:~$ cat /sys/module/zfs/parameters/zfs_scan_idle
0
cr0x@server:~$ cat /sys/module/zfs/parameters/zfs_scan_min_time_ms
1000
Значення: Ці параметри впливають на поведінку сканування. Значення різняться за дистрибутивом/версією, але ви перевіряєте,
чи система налаштована поступатися або працювати агресивно.
Рішення: Якщо scrubs руйнують латентність, збільшуйте yielding/тротлінг (де підтримується), замість простого перенесення графіку.
Завдання 13: Підтвердити налаштування TRIM/autotrim, щоб scrubs не звинувачували за обслуговування SSD
cr0x@server:~$ zpool get autotrim tank
NAME PROPERTY VALUE SOURCE
tank autotrim off default
Значення: Autotrim вимкнено; вивільнення вільного простору на SSD може відбуватися по-іншому і в незручний час.
Рішення: Якщо у вас SSD-пули, вирішіть свідомо: вмикайте autotrim, якщо це підходить для вашого середовища,
і уникайте одночасних важких trim та scrub, якщо це не протестовано.
Завдання 14: Виміряти реальні I/O-патерни додатків під час scrub (не лише статистику ZFS)
cr0x@server:~$ pidstat -d 5 2
Linux 6.8.0 (server) 12/26/2025 _x86_64_ (32 CPU)
10:33:10 UID PID kB_rd/s kB_wr/s kB_ccwr/s Command
10:33:15 999 18321 20480.00 5120.00 0.00 postgres
10:33:15 0 1287 0.00 86016.00 0.00 z_wr_iss
10:33:15 0 1288 327680.00 0.00 0.00 z_rd_iss
10:33:15 UID PID kB_rd/s kB_wr/s kB_ccwr/s Command
10:33:20 999 18321 19456.00 6144.00 0.00 postgres
10:33:20 0 1287 0.00 90112.00 0.00 z_wr_iss
10:33:20 0 1288 335872.00 0.00 0.00 z_rd_iss
Значення: Ви бачите, як kernel-потоки scrub виконують інтенсивні читання, поки база даних також активна.
Рішення: Якщо навантаження чутливе до латентності (бази даних, бекапи VM), плануйте scrubs у менш навантажені вікна або тротльте.
Якщо потрібно запускати під час бізнес-годин — впроваджуйте запобіжні заходи.
Тротлінг і налаштування: як приборкати scrubs
Планування необхідне, але часто недостатнє. У багатьох середовищах ви не знайдете справді простої години.
Scrubs все одно мають виконуватися. Отже, ви контролюєте зону ураження.
Принцип: захищайте латентність, погоджуйтеся на більшу тривалість
Ваші користувачі не переймаються, що scrub завершився за 9 годин замість 14. Їх хвилює, щоб API не таймаутило.
Довший scrub — це нормально, якщо він залишається в межах прийнятного вікна ризику і не перекривається надто часто.
Якщо scrubs стають «завжди увімкненими», це не проблема тротлінгу.
Це проблема потужності та архітектури.
I/O пріоритет на рівні ОС: грубо, але іноді достатньо
На Linux ви часто можете покращити справедливість, запустивши ініціюючий процес scrub з нижчим I/O пріоритетом.
Це не магічно пере-пріоритетизує kernel I/O у всіх випадках, але може допомогти в деяких налаштуваннях. Використовуйте це як важіль, а не догму.
cr0x@server:~$ sudo ionice -c3 zpool scrub tank
cr0x@server:~$ zpool status tank | head -n 6
pool: tank
state: ONLINE
scan: scrub in progress since Thu Dec 26 11:02:01 2025
158G scanned at 510M/s, 92.4G issued at 298M/s, 21.4T total
Значення: Scrub запущено; ви спробували поставити його в I/O-клас idle.
Рішення: Якщо це зменшує вплив на латентність помітно, залиште. Якщо ні — не витрачайте час на марні спроби.
Налаштування сканування ZFS: використовуйте обережно, тестуйте агресивно
OpenZFS відкриває кілки для поведінки сканування (імена і доступність залежать від платформи/версії). Деякі впливають
на те, як робота скану поступається іншим I/O, як довго працюють скан-потоки перед сном, і наскільки агресивно система намагається
використовувати доступну ширину каналу.
Ставтеся до цих налаштувань як до бази даних: дефолт — розумний, зміни мають побічні ефекти, і ви змінюєте тільки з вимірюванням і планом відкату.
Що зазвичай працює:
- Збільшити yielding / idle-поведінку, щоб scrub відступав під навантаженням.
- Зменшити інтенсивність сканування, якщо латентність — головний SLO.
- Тримати пріоритет resilver вищим, ніж scrub; не гальмуйте шлях відновлення.
Що зазвичай підводить:
- Прокручувати агресивність сканування, щоб «закінчити швидше», а потім виявити, що ви не можете запускати scrubs у робочі дні.
- Крутити кілки без розуміння, що пул фактично блокується одним розвалюваним диском (жодне налаштування не виправить фізику).
Планування з урахуванням навантаження краще за хитрий тюнінг
Якщо ваше навантаження має передбачувані сплески — ETL о 01:00, бекапи о 02:00, компакти о 03:00 — не настроюйте ZFS
боротися з цими піками. Перенесіть scrub. Тюнінг потрібен для згладжування країв, а не для ігнорування патернів трафіку.
Механіка планування: cron, systemd таймери та запобіжні заходи
Планування — це не «запустити в неділю». Планування — це «запустити, коли безпечно, і зупинити, коли небезпечно». Це означає, що вам потрібні:
(1) автоматичний тригер, (2) перевірка безпеки, і (3) видимість під час виконання.
Cron: просто, надійно і безпристрасно
Cron підходить, якщо ви додасте wrapper-скрипт, який перевіряє стан пулу, поточне навантаження і чи вже йде скан.
Саме в обгортці живе професіоналізм.
cr0x@server:~$ cat /usr/local/sbin/zfs-scrub-guard
#!/usr/bin/env bash
set -euo pipefail
POOL="${1:-tank}"
# Refuse if a scrub/resilver is already running
if zpool status "$POOL" | grep -qE "scan: (scrub|resilver) in progress"; then
echo "$(date -Is) $POOL: scan already in progress; exiting"
exit 0
fi
# Refuse if pool is degraded
if ! zpool status "$POOL" | grep -q "state: ONLINE"; then
echo "$(date -Is) $POOL: pool not ONLINE; exiting"
exit 1
fi
# Refuse if 1-minute load is too high (example threshold)
LOAD1=$(cut -d' ' -f1 /proc/loadavg)
LOAD1_INT=${LOAD1%.*}
if [ "$LOAD1_INT" -ge 20 ]; then
echo "$(date -Is) $POOL: load too high ($LOAD1); exiting"
exit 0
fi
echo "$(date -Is) $POOL: starting scrub"
exec zpool scrub "$POOL"
cr0x@server:~$ sudo crontab -l
# Scrub on the first Sunday of the month at 01:30
30 1 1-7 * 0 /usr/local/sbin/zfs-scrub-guard tank >> /var/log/zfs-scrub.log 2>&1
Значення: Скрипт не дозволяє перекривати скани, уникає scrub на деградованих пулах і пропускає при високому навантаженні.
Рішення: Налаштуйте пороги для вашого середовища. Якщо у вас немає порога на основі SLO — ви вгадуєте; почніть вимірювати.
systemd таймери: кращий стан, кращі звіти
systemd таймери підходять, коли ви хочете catch-up для пропущених запусків, стандартизовані логи і просте вимкнення/увімкнення.
У продакшні це важливо, бо рано чи пізно у вас буде freeze на обслуговування або інцидент, коли потрібно буде призупинити scrubs.
cr0x@server:~$ cat /etc/systemd/system/zfs-scrub@.service
[Unit]
Description=Guarded ZFS scrub for pool %i
[Service]
Type=oneshot
ExecStart=/usr/local/sbin/zfs-scrub-guard %i
cr0x@server:~$ cat /etc/systemd/system/zfs-scrub@.timer
[Unit]
Description=Monthly ZFS scrub timer for pool %i
[Timer]
OnCalendar=Sun *-*-01..07 01:30:00
Persistent=true
[Install]
WantedBy=timers.target
cr0x@server:~$ sudo systemctl enable --now zfs-scrub@tank.timer
Created symlink /etc/systemd/system/timers.target.wants/zfs-scrub@tank.timer → /etc/systemd/system/zfs-scrub@.timer.
cr0x@server:~$ systemctl list-timers | grep zfs-scrub
Sun 2026-01-04 01:30:00 UTC 1 week 1 day left Sun 2025-12-01 01:30:00 UTC zfs-scrub@tank.timer zfs-scrub@tank.service
Значення: Маєте передбачуваний розклад із персистентністю (пропущені запуски виконуються після простою).
Рішення: Якщо «Persistent=true» спричинить запуск scrub одразу після перезавантаження в пікові години,
відключіть персистентність або додайте перевірку робочих годин.
Запобіжні заходи, що запобігають самонанесенню шкоди
- Не запускайте scrub, якщо активний resilver. Дайте завершитися відновленню.
- Не запускайте scrub на деградованому пулі без потреби. Scrub додасть навантаження в уразливому стані.
- Не запускайте scrubs паралельно на всіх пулах одного хоста. Розтягніть їх; ваш HBA і бекплейн також мають межі.
- Робіть scrubs видимими. Логгируйте старт/фініш у лог, який ви реально читаєте, і алертуйте, якщо «scrub не завершився N днів».
Жарт №2: Якщо ви не можете сказати, коли scrub запустився, він по суті — кот Шредінгера обслуговування — одночасно зроблений і не зроблений, поки не впаде.
Три корпоративні міні-історії з полів scrub
1) Інцидент через неправильне припущення: «scrub — це лише читання»
Середня SaaS-компанія працювала на ZFS-backed VM storage на наборі HDD RAIDZ2 пулів. У них був щомісячний scrub
о 02:00 місцевого часу, бо так робив попередній адміністратор. Все працювало — поки компанія не перемістила частину клієнтів в інший регіон і «тихі години» перестали бути тихими.
On-call побачив сплески латентності і припустив, що scrub не може бути причиною, бо «scrub — це лише читання».
Вони ганялися за мережевими графіками, налаштовували пул підключень бази даних і навіть відкотили реліз.
Тим часом ZFS ремонтував невелику кількість блоків, знайдених під час scrub. Цей ремонт створив записи,
які зіткнулися з синхронними записами гостя VM. Результат — ідеальний шторм глибини черг і хвостової латентності.
Підказка була на виду: zpool status показував ненульові відремонтовані байти і повільний пристрій.
Але ніхто не навчив команду інтерпретувати «issued vs scanned» або ставитися до ремонтної активності як до записового тиску.
Тому scrub продовжувався, клієнти таймаутились, і інцидент тривав довше, ніж треба було.
Виправлення було непоказним: перемістити вікно scrub, додати перевірку завантаження і встановити поріг скасування, прив’язаний до латентності сховища.
Вони також додали алерти, коли під час scrub відремонтовані байти відрізняються від нуля, бо «scrub — це читання» перестало бути хорошою історією.
2) Оптимізація, що підвела: «завершити швидше, зробивши агресивним»
Команда аналітики мала повністю flash пул, що обслуговував кластер запитів. Scrubs ставали довшими з ростом даних, і хтось вирішив «прискорити» їх агресивнішою поведінкою сканування. План: використати максимум пропускної здатності, щоб scrubs встигали до понеділкового ETL.
Це дійсно закінчувалося швидше. Але також це настільки завантажило SSD-контролери, що background garbage collection став видимим у профілі продуктивності.
Сплески латентності з’являлися не під час самого scrub, а одразу після нього, коли контролери намагалися прибрати наслідки. Гірше — ARC був забруднений scrub-читаннями, і query-двигуни втратили локальність кешу.
Команда спочатку думала, що query-двигун «нестабільний». Вони налаштовували додаток, потім ОС, потім мережу. Суть була простішою: вони оптимізували час завершення scrub, а не користувацький досвід.
Вони виграли гонку, яку ніхто не просив бігти.
Відкат навчив: повернути кілки сканування до дефолту, зменшити інтенсивність scrub і розбити scrub на коротші щоденні відрізки замість однієї агресивної сесії.
Час завершення зріс, але хвостова латентність згладилась. Продакшн повернув собі манери.
3) Нудна, але правильна практика, що врятувала день: рознесені scrubs плюс алерти на «один поганий диск»
Інфраструктурна команда фінансової служби вела кілька ZFS пулів на хості, комбінуючи дзеркала для баз даних і RAIDZ для архівів.
Їх політика scrub була банальною: дзеркала щотижня, RAIDZ щомісяця, завжди рознесені по пулах і ніколи не перетиналися з бекапами.
Вони також мали стандартний алерт: «будь-який vdev з await в 3 рази вищим за сусідів під час scrub» — тригер для розслідування.
Одного кварталу, під час рутинного дзеркального scrub, алерт спрацював для одного SSD, який ще був ONLINE з нульовими ZFS-помилками.
Пристрій не падав голосно. Він тихо падав, іноді затримуючись довго достатньо, щоб створити хвостовий спайк латентності.
Оскільки команда дивилася на поведінку по vdev під час scrub, вони побачили це рано — до того, як база даних стала жертвою.
Вони поміняли пристрій у заплановане вікно. Тиждень потому SMART показав погіршення.
Іншими словами: нудна практика зловила проблему раніше, ніж вона стала інцидентом.
Ніхто не отримав трофей. Ніхто не писав постмортем. Ось у чому суть.
Поширені помилки: симптом → причина → виправлення
1) Симптом: «Кожен scrub триває довше, ніж попередній»
Причина: Фрагментація пулу та ріст; доданий обсяг збільшує набір сканування; один диск старіє; або scrubs перекриваються з більшими навантаженнями при зміні використання.
Виправлення: Виявляйте відстаючі vdev-и за допомогою zpool iostat -v. Проактивно міняйте повільні пристрої. Перегляньте вікно. Якщо scrubs не встигають між вікнами, змініть частоту або збільшіть паралелізм vdev.
2) Симптом: «Латентність стрибає лише під час scrub; пропускна здатність виглядає нормально»
Причина: Насичення глибини черги. Scrub споживає робочий час диска, шкодячи малому синхронному I/O.
Виправлення: Тротльте scrub (платформні кілки, нижчий I/O пріоритет), переносіть вікно і встановлюйте пороги скасування на основі p95/p99 латентності, а не MB/s.
3) Симптом: «ETA scrub стрибає»
Причина: Конкурентні навантаження або vdev, що періодично зависає; іноді проблеми контролера/HBA.
Виправлення: Корелюйте з iostat -x і per-vdev zpool iostat -v. Перевіряйте zpool events -v на помилки вводу-виводу/таймаути. Розслідуйте кабелі/бекплейн, якщо зупинки стрибкоподібні на декількох дисках.
4) Симптом: «Scrub знаходить помилки контрольних сум, але пул залишається ONLINE»
Причина: ZFS відновив із надлишковості; присутні проблеми з носієм або шляхом.
Виправлення: Розглядайте як апаратний/шляховий інцидент. Отримайте SMART, перевірте логи контролера і плануйте заміну пристрою, якщо помилки повторюються. «Scrub виправив» не означає «проблема вирішена».
5) Симптом: «Scrubs завжди запущені; немає тихого періоду»
Причина: Тривалість scrub перевищує частоту, часто через величезну ємність з недостатнім паралелізмом vdev або постійне навантаження.
Виправлення: Збільшіть паралелізм (більше vdev-ів), зменшіть churn даних де можливо, погодьтеся на рідші scrubs з прицільним моніторингом і забезпечте достатній запас продуктивності для обслуговування.
6) Симптом: «Після включення агресивних налаштувань scrubs швидші, але наступного дня — повільніше»
Причина: Забруднення кешу, побічні ефекти SSD GC або порушені I/O патерни. Ви перемістили біль, а не усунули його.
Виправлення: Поверніть значення за замовчуванням, запускайте scrubs у менших шматках, і вимірюйте латентність протягом 24 годин — не лише під час вікна scrub.
7) Симптом: «Scrub стартує одразу після перезавантаження і шкодить піковому трафіку»
Причина: Персистентність таймерів systemd або поведінка catch-up, що спрацьовує одразу після завантаження.
Виправлення: Вимкніть персистентність або додайте перевірки часу доби/робочих годин. Впровадьте «час стабілізації після перезавантаження» як правило.
8) Симптом: «Scrub повільний лише на одному пулі, на одному хості»
Причина: Проблеми конкретного HBA-лану/бекплейна, один маргінальний диск або інша геометрія vdev, ніж ви припускали.
Виправлення: Порівняйте розкладки vdev, підтвердіть швидкості лінків і використовуйте per-vdev iostat, щоб знайти відмінника. Замінюйте апаратне, а не надіятись на диво.
Чеклісти / покроковий план
Покроково: встановіть розклад scrub, який не зашкодить піковим годин
- Виміряйте базову латентність і використання протягом тижня. Потрібні p95/p99 дискової латентності і per-vdev використання, а не лише пропускна здатність пулу.
- Запустіть контрольований тест scrub у низькоризиковому вікні. Зафіксуйте дельту латентності і швидкість сканування.
- Виберіть вікно на основі даних, а не традиції. Якщо ваш «off-peak» — час бекапів, не йдіть проти цього.
- Визначте пороги скасування (латентність, сплески помилок, порушення SLO клієнтів). Вирішіть, хто може скасувати scrub і коли.
- Додайте запобіжні заходи: пропуск при пулі не-ONLINE, пропуск при resilver, пропуск при високому навантаженні, пропуск якщо бекапи активні.
- Рознесіть scrubs по пулах на одному хості і по кластерам. Якщо всі scrubs стартують одночасно — ви створили новий піковий час.
- Логуйте і алертуйте на завершення. «Scrub не завершився за N днів» — це операційний сигнал, а не цікавинка.
- Переглядайте результати щомісяця: тренди тривалості, знайдені помилки, відремонтовані байти, поведінка найповільнішого vdev.
Чекліст: перед запуском scrub у продакшні
- Пул у стані ONLINE; немає активного resilver.
- Немає відомих проблемних дисків; SMART і ZFS-лічильники стабільні.
- Бекапи/ETL/пакетні задачі не накладаються.
- У вас є видимість per-vdev I/O та латентності в моніторингу.
- Ви маєте чіткі критерії скасування і план перенесення.
Чекліст: після завершення scrub
- Підтвердьте «errors: No known data errors» і перегляньте відремонтовані байти.
- Порівняйте тривалість і швидкість сканування з попереднім запуском; розслідуйте регресії.
- Виявте vdev-отлایери (повільні або проблемні) і створіть тікет на подальші дії.
- Занотуйте, чи вікно спричинило видимий вплив користувачів. Якщо так — відкоригуйте.
Питання та відповіді
1) Чи запускати ZFS scrubs щотижня чи щомісяця?
Щомісяця — це поширений старт, але визначайте частоту за тривалістю scrub і рівнем ризику. Якщо scrubs тривають кілька днів,
щомісяця перетворюється на постійне навантаження — або скрабте рідше, або перероблюйте архітектуру для більшого паралелізму.
2) Чи безпечно scrub під час бізнес-годин?
Може бути, якщо ви тротлите і маєте запас потужності. Якщо ви не знаєте свого запасу — вважайте, що його немає.
Для чутливих до латентності навантажень — плануйте вікна поза піковими або впровадьте перевірки навантаження/латентності.
3) Чому scrub впливає на записи, якщо це читаюча операція?
Тому що коли ZFS знаходить погані дані і надлишковість дозволяє відновити, він перезаписує виправлені дані. Також scrub конкурує за
робочий час диска, що непрямо уповільнює операції запису.
4) В чому різниця між «scanned» і «issued» в zpool status?
«Scanned» відображає пройдений набір роботи; «issued» — I/O, фактично відправлені. Великий розрив може вказувати на тротлінг,
конкуренцію або зависання. Використовуйте per-vdev статистику, щоб знайти, де вузьке місце.
5) Чи скасовувати scrub, коли продуктивність падає?
Якщо клієнти постраждали і пул здоровий — скасування і перенесення розумні. Якщо активний resilver — будьте набагато обережнішими:
швидкість відновлення важливіша за комфорт.
6) Чи зношують scrubs SSD?
Scrubs переважно читання, але ремонти спричинюють записи, а тривалі читання все одно споживають пропускну здатність контролера і можуть
запускати фонове обслуговування. Більший ризик — не «знос», а вплив на продуктивність і приховане деградоване пристрій.
7) Чи можна скрабити лише частину пулу?
Scrub працює на рівні пулу. Ви не можете надійно проскрубити «лише цей датасет» для перевірки цілісності. Плануйте вікна й інтенсивність, виходячи з того, що робота охоплює весь пул.
8) Мій пул величезний. Як уникнути scrub, що ніколи не завершується?
Спочатку з’ясуйте, чому він повільний: відстаючі vdev-и, конфлікти з навантаженнями або недостатній паралелізм. Якщо пул просто не поміщається у розумні вікна,
потрібна архітектурна зміна (більше vdev-ів, інша розкладка) або перегляд ризик-позиції з потужним моніторингом.
9) Чи потрібен scrub, якщо у мене є бекапи?
Бекапи — це не перевірка цілісності для первинного сховища. Scrub виявляє і ремонтує корупцію до того, як ви знайдете її під час відновлення — коли час проти вас.
10) Як зрозуміти, що диск «повільний, але не ламається»?
Порівнюйте per-vdev використання і await під час scrub. Якщо один диск постійно має набагато вищий await/%util ніж сусіди,
тримайте його в підозрі навіть при нульових ZFS-помилках. Тихі відмови люблять бути проігнорованими.
Наступні кроки, які не зіпсують вам тиждень
ZFS scrubs необхідні, якщо вам не байдужа цілісність даних. Але вам не потрібно дозволяти їм пригнітити ваші пікові години.
Зробіть scrubs нудними: передбачувані вікна, контрольована інтенсивність і гучні сигнали, коли щось не так.
- Обирайте вікно scrub за даними латентності, а не за звичкою.
- Додайте guard-скрипт, який відмовляється запускати scrubs під навантаженням, під час resilver або на деградованих пулах.
- Інструментуйте поведінку per-vdev, щоб «один поганий диск» виявляли раніше.
- Визначте критерії скасування, прив’язані до впливу на клієнтів, і відрепетируйте рішення.
- Переглядайте тренди scrub щомісяця; якщо тривалість зростає, виправляйте архітектуру або апарат до того, як пул прийме рішення за вас.
Зробіть це — і scrubs стануть тим, чим і мають бути: рутинними перевірками цілісності, а не несподіваними експериментами з продуктивністю для ваших користувачів.