Ви збудували цілком нормальний пул ZFS. Потім поставили його за SAS-експандером, бо «це ж просто проводка, правда?» Тепер scrub-і тривають вічність, resilver-и повзуть, а графік латентності нагадує сейсмограму під час дрібної апокаліпсичної події.
У цьому місці багато хто звинувачує ZFS. Не треба. Зазвичай справа в топології та арифметиці лінків: oversubscription, вузькі порти, черги, арбітраж експандера або HBA, який тихо прищемлений на PCIe. Добра новина: ви можете швидко діагностувати це й виправити, не перетворюючи стелаж для дисків на сучасне мистецтво.
Ментальна модель, яка не підведе
SAS-експандер — це комутатор пакетів для SAS-кадрів. Оце й усе. Це не чарівний множник пропускної здатності. Він дає фан-аут (багато дисків) за менше число upstream-лінків (до вашого HBA) і планує доступ до цих лінків. Якщо сукупний попит downstream перевищує upstream-можливості, ви не отримуєте більше throughput — ви отримуєте конкуренцію, черги та зростання латентності.
Коли ZFS виконує великі послідовні читання, ви можете «протягнутися» з oversubscribed експандером, бо диски повільні й передбачувані. Коли ZFS робить scrub-и, resilver-и, прогулянки метаданими та багато одночасних дрібних I/O, експандери навантажуються так, що на рівні додатку це виглядає як «виплески випадкової латентності».
Три рівні, що можуть стати вузьким місцем (і часто стають)
- Носій: поведінка HDD/SSD, SATA vs SAS, NCQ/TCQ, прошивки з особливостями.
- Транспорт: SAS-лінки, wide-порти, арбітраж експандера, SATA tunneling (STP), зонування.
- Хост: глибина черги HBA, налаштування драйвера, PCIe-лени, обробка переривань, навантаження CPU, планування ZFS.
Завдання — визначити, який рівень обмежує вас саме зараз. Не теоретично. Не по даташиту. А на вашій стійці опівночі, поки таймер resilver сміється над вами.
Жарт #1: SAS-експандер нагадує офіс відкритого планування — усі можуть співпрацювати, але чомусь ніхто не встигає працювати у пікові години.
Факти та історія: чому експандери поводяться так
Трохи контексту допомагає, бо SAS має довгу історію інженерних рішень. Ось конкретні пункти, що зустрічаються в реальних системах:
- SAS-експандери походять від ідей комутаторів Fibre Channel, але з простішою адресацією та іншим арбітражним механізмом. Інтуїція «це комутатор» правильна, але реалізація відрізняється.
- SAS-1 (3 Gb/s), SAS-2 (6 Gb/s), SAS-3 (12 Gb/s) — це швидкості на lane; wide-порти об’єднують lanes (x2, x4 тощо). Ваша «12G полиця» може фактично бути «6G-ish», якщо вона знизила швидкість переговору.
- SATA-диски за SAS-експандером використовують STP (SATA Tunneling Protocol), яке при навантаженні поводиться інакше, ніж рідний SAS. Деякі експандери погано справляються з конкуренцією в STP.
- Ранні експандери SAS-2 мали сумнівні прошивки: скиди лінків при помилках, погана справедливість і дивні взаємодії з певними прошивками HBA. Стало краще, але «оновіть прошивку» досі не є забобоном.
- Wide-porting існує, бо одна lane не завжди достатня. Одна 12G lane чудова, доки ви не посадите за неї 24 диски й не запустите scrub.
- Зонування на SAS-експандерах — реальна річ, і неправильна конфігурація зможе змусити трафік йти вузьким шляхом або перешкодити роботі multipath, навіть якщо кабель фізично присутній.
- Налаштування глибини черги було спортом ще за часів SCSI. Занадто низька — марнує апарат; занадто висока — призводить до розвалу латентності. Сучасний Linux дозволяє легко задавати — і легко зробити помилку.
- PCIe став тихим обмежувачем, поки SAS розігнався. «12G HBA» на недостатніх PCIe-ленах може стати вузьким місцем задовго до того, як SAS-мережа насичується.
Одна інженерна цитата для кишені, коли хочеться оптимізувати без вимірювання: «Якщо ти не можеш виміряти — ти не можеш покращити.» — Peter Drucker. (Зазвичай приписується так, сприймайте як перефразовану ідею, якщо ви педант.)
Топологія й математика oversubscription (де ховані трупи)
Поговорімо про найпоширенішу помилку: у вас багато дисків, а upstream-ширина недостатня.
Знайте свої lanes і припиніть гадати
Пропускна здатність SAS — на lane, в обох напрямах, приблизно:
- 6G SAS: ~600 MB/s на lane після кодування/накладних витрат (приблизно).
- 12G SAS: ~1200 MB/s на lane після накладних витрат (прибл.).
Wide-порти об’єднують lanes. x4 12G wide-порт — це приблизно «до ~4.8 GB/s в кожен бік» в ідеалі. Ідеальні випадки рідкість у продакшені, але математика допомагає зрозуміти, чи ви мрієте.
Oversubscription не завжди зло
Oversubscription нормальний, бо диски не працюють на лінійному максимумі одночасно. У HDD кожен диск може давати ~200–280 MB/s послідовно, і значно менше при випадковому I/O. Ви можете oversubscribe і бути в порядку, якщо:
- робочі навантаження спалахові й не синхронізовані між шпинделями,
- є достатньо кешу (ARC/L2ARC) для поглинання читань,
- не запускаєте scrub/resilver у пік або обмежуєте їх розумно.
Але операції обслуговування ZFS — це синхронізовані навантаження. scrub торкається всього. resilver торкається багато й робить це, коли пул вже деградований. Якщо uplink експандера вузький, ці операції перетворюються на повільну дорожню пробку.
Типові топології та їх пастки
- Один порт HBA → один uplink експандера → багато дисків: найпростіша конфігурація й найлегше насичується.
- Два порти HBA → подвійні uplinks до того самого експандера: може допомогти, але лише якщо wide-porting або multipath дійсно домовлені й експандер налаштований відповідно.
- Подвійні експандери (редундантні шляхи) у полиці: добре для доступності; продуктивність залежить від балансу трафіку і того, чи бачить ОС окремі шляхи.
- Дейзі-чейн експандерів: працює, але легко створити «воронку», де все йде через один лінк. Латентні сплески стають вашою особливістю.
IO-патерни ZFS, що навантажують експандери
ZFS — це не «контролер RAID». Це система зберігання, що планує I/O на основі transaction groups, layout vdev та політик чергування. Це важливо, бо експандери чутливі до паралелізму і справедливості.
Scrub/resilver: великий фан-аут, стійке навантаження, чутливість до справедливості
Під час scrub ZFS читає весь пул, щоб перевірити контрольні суми. Це: багато дисків, багато одночасних читань і стабільний тиск годинами чи днями. Oversubscribed uplink стає спільним горлечком, а експандери можуть додатково вносити латентність, коли арбітражні цикли завантажені.
Випадкові дрібні I/O: метадані і синхронні навантаження
Навіть якщо ваш додаток виконує «великі потокові записи», метадані ZFS, непрямі блоки й політика алокації генерують дрібніші I/O. Експандери не «терплять» дрібні I/O; вони терпіли б, якби не велика кількість незавершених команд, що конкурують за обмежений uplink, особливо з SATA за STP.
Спеціальні vdev та SLOG можуть допомогти, але також маскують проблеми транспорту
Спеціальний vdev може зменшити метадані на HDD-відрі. SLOG може змінити латентність sync-записів. Жоден з них не збільшує ширину uplink експандера. Вони можуть зменшити попит — і це добре — але не плутайте «симптоми покращилися» з «фабрика виправлена».
Жарт #2: Оцінки часу resilver — як прогноз погоди: технічно виведені, емоційно неточні.
Швидкий план діагностики
Ви на чергуванні. Латентність висока. scrub запущено. Хтось каже «полиця повільна». Ось швидка послідовність, що знаходить вузьке місце частіше, ніж ні.
По-перше: доведіть, чи вузьке місце в SAS-фабриці або в самих дисках
- Перевірте латентність vdev у ZFS (всі vdev однаково повільні чи тільки одна сторона?): використайте
zpool iostat -v. - Перегляньте час обслуговування диска та черги: використайте
iostat -xі подивіться наawait/svctm-подібні проксі (r_await/w_await), використання та queue depth. - Перевірте переговори лінку та топологію: використайте
systool/lsscsi/sas2ircu/storcli(в залежності від HBA), щоб підтвердити 12G/6G і кількість lanes.
По-друге: перевірте, чи насичується uplink
- Виміряйте сукупний throughput під час scrub/resilver і порівняйте з теоретичним uplink: чи є підозрілий плато?
- Шукайте проблеми зі справедливістю: деякі диски показують величезні черги, а інші — простій; класична ознака арбітражу експандера або проблем з шляхами.
- Шукайте скиди/повтори: помилки лінку викликають ретрансляції й зупинки, що імітують «повільне сховище».
По-третє: виключіть обмеження на стороні хоста
- Перевірте ширину/швидкість PCIe у HBA.
- Перевірте тиск softirq/переривань у CPU, якщо ви маєте дуже високі IOPS (SSD за експандером можуть це робити).
- Перевірте налаштування глибини черги для SCSI-пристроїв і драйвера HBA/модуля.
Якщо ви зробите лише три речі: zpool iostat -v, iostat -x і «яку швидкість/ширину домовився HBA», ви зловите більшість реальних помилок.
Практичні завдання: команди, виводи та що вирішувати
Це не бенчмаркові фото для Instagram. Це команди, які ви запускаєте, коли хтось чекає у Slack на відповідь. Кожне завдання включає, що означає вивід і яке рішення прийняти далі.
Завдання 1: Визначити латентність по всьому пулу й чи локалізована вона
cr0x@server:~$ zpool iostat -v tank 5 3
capacity operations bandwidth
pool alloc free read write read write
--------------------------- ----- ----- ----- ----- ----- -----
tank 120T 80.0T 1.20K 220 1.10G 180M
raidz2-0 60T 40.0T 620 120 560M 95M
sda - - 78 15 70M 12M
sdb - - 77 14 70M 12M
sdc - - 76 15 69M 12M
raidz2-1 60T 40.0T 580 100 540M 85M
sdd - - 74 13 68M 11M
sde - - 12 2 10M 1.5M
sdf - - 73 13 67M 11M
--------------------------- ----- ----- ----- ----- ----- -----
Що це означає: Один диск (sde) значно відстає, тоді як інші стабільні. Це не просто історія про насичення uplink; це пахне проблемним диском, шляхом або зниженням переговорів лінку.
Рішення: Заглибтесь у sde: перевірте переговори швидкості, лічильники помилок, кабелі та SMART. Не чіпайте ZFS-тюнінг, поки не з’ясуєте, чи не ламається окремий диск/шлях.
Завдання 2: Перевірити статус scrub і чи він обмежується
cr0x@server:~$ zpool status -v tank
pool: tank
state: ONLINE
scan: scrub in progress since Thu Dec 26 01:12:03 2025
14.2T scanned at 1.05G/s, 9.8T issued at 720M/s, 200K repaired
18.4% done, 0 days 10:22:11 to go
config:
NAME STATE READ WRITE CKSUM
tank ONLINE 0 0 0
raidz2-0 ONLINE 0 0 0
raidz2-1 ONLINE 0 0 0
errors: No known data errors
Що це означає: Різниця між «scanned at» і «issued at» вказує, що scrub обмежений фактичним випуском I/O пристроями (або якимись обмеженнями), а не лише обходом метаданих.
Рішення: Якщо вплив на латентність неприйнятний, розгляньте тимчасове обмеження через ZFS-тюнінги (залежно від платформи) або планування scrub поза піками. Якщо «issued at» значно нижче, ніж можуть диски, підозрюйте uplink експандера або обмеження чергування.
Завдання 3: Побачити використання кожного диска та час очікування
cr0x@server:~$ iostat -x -d 5 2
Linux 6.6.0 (server) 12/26/2025 _x86_64_ (32 CPU)
Device r/s w/s rMB/s wMB/s r_await w_await aqu-sz %util
sda 78.2 14.9 70.5 12.1 9.2 12.3 1.2 88.0
sdb 77.9 14.7 70.3 12.0 9.4 12.1 1.2 87.5
sdc 76.8 15.1 69.5 12.2 9.6 12.0 1.3 89.1
sdd 74.0 13.4 68.1 11.0 9.1 11.8 1.1 86.2
sde 11.7 2.0 10.2 1.6 55.0 61.2 3.8 42.0
sdf 73.2 13.1 67.4 10.8 9.0 11.6 1.1 85.9
Що це означає: sde має високий await і більший середній розмір черги, але низький throughput і нижче %util. Класична ознака «чекає не на поверхню диска»: повтори, скиди лінку, проблеми шляху або дивна поведінка експандера.
Рішення: Перевірте журнали ядра на предмет помилок лінку і дізнайтеся швидкість переговорів SAS для цього таргета. Не підвищуйте depth черги, щоб «полагодити» це — це лише погіршить хвостову латентність.
Завдання 4: Знайти SAS-хости та експандер(и), видимі в Linux
cr0x@server:~$ lsscsi -g
[0:0:0:0] disk ATA ST12000NM000J SN02 /dev/sda /dev/sg0
[0:0:1:0] disk ATA ST12000NM000J SN02 /dev/sdb /dev/sg1
[0:0:2:0] disk ATA ST12000NM000J SN02 /dev/sdc /dev/sg2
[0:0:3:0] disk ATA ST12000NM000J SN02 /dev/sdd /dev/sg3
[0:0:4:0] disk ATA ST12000NM000J SN02 /dev/sde /dev/sg4
[0:0:5:0] disk ATA ST12000NM000J SN02 /dev/sdf /dev/sg5
[1:0:0:0] enclosu HGST H4060-J 4R06 - /dev/sg10
Що це означає: У вас принаймні два SCSI-хости ([0:...] і [1:...]) і пристрій enclosure. Такий запис зазвичай вказує на SES (enclosure services), що часто буває в стелажах з експандерами.
Рішення: Відобразіть диски на топологію expander/phy за допомогою утиліт HBA (LSI/Broadcom) або атрибутів sysfs. Потрібно знати: чи «повільні диски» згруповані за одним портом експандера?
Завдання 5: Перевірити журнали ядра на предмет скидів SAS-лінків, таймаутів і помилок транспорту
cr0x@server:~$ dmesg -T | egrep -i 'sas|mpt3sas|scsi|reset|timeout|link'
[Thu Dec 26 02:01:14 2025] mpt3sas_cm0: log_info(0x31120400): originator(PL), code(0x12), sub_code(0x0400)
[Thu Dec 26 02:01:15 2025] sd 0:0:4:0: [sde] tag#1826 FAILED Result: hostbyte=DID_SOFT_ERROR driverbyte=DRIVER_OK
[Thu Dec 26 02:01:15 2025] sd 0:0:4:0: [sde] tag#1826 Sense Key : Aborted Command [current]
[Thu Dec 26 02:01:15 2025] mpt3sas_cm0: sas_device(0x00000008), phy(6) link reset
[Thu Dec 26 02:01:17 2025] sd 0:0:4:0: [sde] Synchronizing SCSI cache
Що це означає: М’які помилки і скиди лінку на конкретному phy сильно вказують на проблему фізичного рівня (кабель, роз’єм, слот на бекплейні, phy експандера) або маргінальні переговори на високій швидкості.
Рішення: До того як чіпати ZFS-тюнінг, виправте надійність транспорту: пересівайте/заміни кабель, пересуньте диск у інший відсік, перевірте сумісність прошивок експандера й HBA. Налаштування продуктивності на ненадійному лінку — це полірування тріснутого об’єктива.
Завдання 6: Перевірити швидкість/ширину PCIe у HBA
cr0x@server:~$ lspci -nn | egrep -i 'sas|scsi'
3b:00.0 Serial Attached SCSI controller [0107]: Broadcom / LSI SAS3008 PCI-Express Fusion-MPT SAS-3 [1000:0097] (rev 02)
cr0x@server:~$ sudo lspci -s 3b:00.0 -vv | egrep -i 'LnkCap|LnkSta'
LnkCap: Port #0, Speed 8GT/s, Width x8, ASPM not supported
LnkSta: Speed 8GT/s, Width x4
Що це означає: Картка може працювати як PCIe Gen3 x8, але наразі працює як x4. Це підступне обмеження пропускної здатності і може викликати «таємниче» насичення, навіть якщо SAS-uplink широкий.
Рішення: Перемістіть HBA в слот з повними ланами, налаштуйте BIOS bifurcation або приберіть конфліктний пристрій, що краде лани. Не сперечайтеся з фізикою.
Завдання 7: Перевірити глибину черги SCSI на пристрої
cr0x@server:~$ for d in sda sdb sdc sdd sde sdf; do echo -n "$d "; cat /sys/block/$d/device/queue_depth; done
sda 32
sdb 32
sdc 32
sdd 32
sde 32
sdf 32
Що це означає: Глибина черги 32 — поширена для SATA-дисків за SAS. Не обов’язково погано.
Рішення: Якщо ви насичуєте uplink, підвищення глибини черги може погіршити латентність, бо збільшує кількість незавершених робіт, що конкурують за той самий вузький лінк. Якщо ви недовантажуєте швидкі SSD і латентність стабільна, підвищення може допомогти. Рішення приймайте на підставі вимірів, а не відчуттів.
Завдання 8: Перевірити планувальник блочного шару (допомагає діагностувати підсилення латентності)
cr0x@server:~$ cat /sys/block/sda/queue/scheduler
[mq-deadline] none kyber bfq
Що це означає: Активний mq-deadline. Це часто розумно для HDD на серверах.
Рішення: Якщо ви бачите патологічну хвостову латентність при змішаних навантаженнях за експандером, mq-deadline зазвичай кращий старт, ніж none для HDD. Не копіюйте бездумно «none усюди».
Завдання 9: Перевірити переговорену швидкість лінку на рівні пристрою (SAS/SATA)
cr0x@server:~$ sudo smartctl -a /dev/sde | egrep -i 'SATA Version|SAS Version|Negotiated|Transport protocol'
SATA Version is: SATA 3.3, 6.0 Gb/s (current: 3.0 Gb/s)
Що це означає: Диск підтримує 6.0 Gb/s, але наразі працює на 3.0 Gb/s. Це палючий вулик для маргінального лінку.
Рішення: Ставтеся до «negotiated down» як до апаратної/кабельної/бекплейн-проблеми перш за все. Виправте це, потім перетестуйте. Якщо таке повторюється, підозрюйте конкретний відсік або phy експандера.
Завдання 10: Співвіднести диски зі слотами enclosure (щоб рухати потрібний елемент)
cr0x@server:~$ sudo sg_map -x
/dev/sg0 0 0 0 0 /dev/sda
/dev/sg1 0 0 1 0 /dev/sdb
/dev/sg2 0 0 2 0 /dev/sdc
/dev/sg3 0 0 3 0 /dev/sdd
/dev/sg4 0 0 4 0 /dev/sde
/dev/sg5 0 0 5 0 /dev/sdf
/dev/sg10 1 0 0 0
Що це означає: Тепер ви можете корелювати SCSI-адреси з дисками. Якщо у вас є SES-утиліти, часто можна підсвітити LED або дізнатися мапінг слотів.
Рішення: Якщо проблемний лише один phy/слот, пересуньте диск в інший відсік, щоб перевірити, чи проблема «переїде» з диском (проблема диска) або залишиться з відсіком (бекплейн/шлях експандера).
Завдання 11: Спостерігати латентність ZFS під навантаженням з видимістю по vdev
cr0x@server:~$ zpool iostat -v -l tank 5 2
capacity operations bandwidth total_wait disk_wait
pool alloc free read write read write read write read write
-------------------------- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----
tank 120T 80.0T 1.15K 240 1.05G 190M 12ms 8ms 9ms 6ms
raidz2-0 60T 40.0T 600 120 530M 95M 11ms 7ms 8ms 5ms
raidz2-1 60T 40.0T 550 120 520M 95M 13ms 9ms 10ms 7ms
-------------------------- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----
Що це означає: total_wait включає час у чергах ZFS; disk_wait ближчий до часу обслуговування пристрою. Коли total_wait зростає, а disk_wait залишається помірним, ви заблоковані вище за диски (черги в ZFS, HBA або фабриці).
Рішення: Якщо обидва значення високі — диски або транспорт до них повільні. Якщо тільки total високий — дивіться на глибину черги, обмеження scrub/resilver і контенцію на хості.
Завдання 12: Перевірити поточні ZFS-тюнінги, що впливають на поведінку scrub/resilver (Linux OpenZFS)
cr0x@server:~$ sudo sysctl -a 2>/dev/null | egrep 'zfs\.(vdev|scan)' | head -n 12
zfs.vdev.max_active=1000
zfs.vdev.scrub_max_active=64
zfs.vdev.resilver_max_active=64
zfs.vdev.async_read_max_active=64
zfs.vdev.async_write_max_active=64
zfs.vdev.sync_read_max_active=10
zfs.vdev.sync_write_max_active=10
zfs.scan.issue_strategy=0
Що це означає: Ці параметри контролюють, скільки одночасних I/O ZFS буде кидати на vdev для різних класів роботи. Висока конкуренція може наситити uplink експандера і підняти латентність для «реальної» роботи. Низька конкуренція може зробити обслуговування надто довгим.
Рішення: Якщо ви бачите насичення експандера під час scrub/resilver, спочатку зменшіть concurrency цих операцій і спостерігайте. Якщо ви недовантажуєте fabric і диски, обережно підвищуйте. Міняйте по одному параметру й збирайте метрики.
Завдання 13: Підтвердити, що multipath дійсно працює (якщо ви цього очікуєте)
cr0x@server:~$ multipath -ll
mpatha (3600508b1001c3d6d5f3c1b2a00000001) dm-2 LIO-ORG ,disk
size=10T features='1 queue_if_no_path' hwhandler='0' wp=rw
|-+- policy='service-time 0' prio=50 status=active
| `- 3:0:0:0 sda 8:0 active ready running
`-+- policy='service-time 0' prio=10 status=enabled
`- 4:0:0:0 sda 8:0 active ready running
Що це означає: У вас є кілька шляхів. Чудово — якщо вони незалежні uplinks, а не два шляхи, що сходяться в один вузький uplink експандера.
Рішення: Перевірте фізичне підключення і маршрутизацію експандера. Multipath — не гарантія продуктивності; це інструмент для коректності/доступності, який також може допомогти throughput, якщо топологія дозволяє.
Завдання 14: Виміряти сукупний throughput під час scrub/resilver, щоб помітити плато uplink
cr0x@server:~$ zpool iostat tank 1 5
capacity operations bandwidth
pool alloc free read write read write
---------- ----- ----- ----- ----- ----- -----
tank 120T 80.0T 1.10K 210 1.15G 160M
tank 120T 80.0T 1.12K 215 1.16G 162M
tank 120T 80.0T 1.11K 212 1.15G 161M
tank 120T 80.0T 1.11K 211 1.15G 160M
tank 120T 80.0T 1.10K 209 1.14G 159M
Що це означає: Стабільне плато (тут ~1.15 GB/s читання) не завжди погано. Стає підозрілим, якщо ваша теоретична швидкість uplink близька до цієї величини, а у вас багато шпинделів, які під час scrub могли б сумарно її перевищити.
Рішення: Порівняйте плато з ємністю uplink (lanes × negotiated rate). Якщо ви близько — ви uplink-bound. Виправлення: додайте lanes (ширші порти), додайте ще uplink або розподіліть полиці між HBA.
Завдання 15: Перевірити версії прошивки/драйвера HBA (бо сумісність — це функція продуктивності)
cr0x@server:~$ modinfo mpt3sas | egrep -i 'version|firmware'
version: 46.100.00.00
firmware: 16.00.12.00
Що це означає: Ви принаймні знаєте, що стоїть у системі. Несумісності прошивок експандера та HBA можуть проявлятися як скиди, зниження швидкості переговорів або погана справедливість під навантаженням.
Рішення: Якщо ви ганяєтеся за інтермітентними скидами або пониженнями переговорів, узгодьте прошивку HBA з відомо-робочим набором для вашої полиці/покоління експандера. Робіть зміни у вікні обслуговування й валідуйте стрес-тестом + scrub.
Реальні важелі тюнінгу
1) Спочатку виправте фізичний та лінковий рівень
Якщо у вас є скиди лінків, переговорені зниження швидкості або CRC-помилки — зупиніться. Замініть кабелі, пересійте роз’єми, пересуньте в інший слот, оновіть прошивки. Тюнінг вище цього рівня — як налаштовувати гоночний болід із трьома відсутніми гайками.
2) Віддавайте перевагу wide-портам і реальній upstream-пропускній здатності
Якщо експандер має кілька зовнішніх портів, вам потрібно або:
- Wide-porting: кілька lanes, агрегованих між HBA і експандером, або
- Кілька незалежних uplink-ів, розподілених по полиці/vdev, щоб один uplink не став воронкою.
Практично: підключайте полицю так, як постачальник радить для «високої пропускної здатності», а не так, щоб використовувати найменше кабелів. Кабелі дешеві. Час на чергуванні — ні.
3) Обмеження concurrency scrub/resilver: підлаштуйте під можливості фабрики, а не під его
В OpenZFS (Linux) параметри zfs.vdev.scrub_max_active і zfs.vdev.resilver_max_active — перші, до яких варто доторкнутися, коли операції обслуговування вбивають латентність.
Рекомендація, що здивовано добре працює за oversubscribed експандерів:
- Почніть з 16–32 scrub/resilver max_active на клас vdev, якщо у вас HDD за експандером.
- Якщо латентність стабільна і ви не насичуєте uplink, поступово збільшуйте.
- Якщо з’являються хвостові пики латентності — зменшуйте й вимірюйте знову.
Ці значення не сакральні. Сакральне — міняти одну річ за раз і збирати метрики до/після.
4) Глибина черги: не «виправляйте» брак пропускної здатності більше чергами
Глибина черги — це множник контенції. Якщо ваш uplink вже насичений, підвищення depth збільшує кількість робіт, що чекають своєї черги, зростає латентність, додатки страждають, ви страждаєте.
Коли її підвищувати?
- SSD за правильно широкою SAS-фабрикою, де HBA не є обмеженням.
- Навантаження, орієнтовані на пропускну здатність і що терплять вищу латентність (бекапи, масова реплікація).
5) Розподіляйте пули/vdev по різних fabrics, коли можете
Продуктивність ZFS живе й помирає від паралелізму vdev. Якщо у вас два HBA або дві полиці — не ставте всі vdev за одним uplink експандера, бо «так компактніше». Розподіліть vdev так, щоб жоден лінк не став спільною воронкою для всього пулу. Це про дизайн, а не про тюнінг.
6) Перевіряйте PCIe і розміщення по NUMA
Якщо ваш HBA працює як x4 замість x8, або підключений до «іншого сокету» з NUMA-пеналті — ви даремно витрачаєте час, звинувачуючи експандер. Підтвердіть ширину/швидкість PCIe і тримайте переривання/CPU локальність адекватними для систем з високим IOPS.
7) Обережно з політиками «оптимізувати швидкість rebuild»
Швидкі resilver-и — це чудово, доки вони не задушать продуктивність. На oversubscribed полицях агресивна concurrency resilver-ів може наситити uplink і погіршити роботу всіх даних, навіть тих на «здорових» vdev. Мета — передбачувана сервісність, а не перемога в банері бенчмарку.
Три корпоративні міні-історії з передової
Інцидент через хибне припущення: «12G полиця означає 12G усюди»
Конфігурація виглядала сучасно: SAS3 HBA, SAS3 полиця, на передній панелі «12G». Команда перенесла в неї ціль для бекапів, потім перепризначила під щось інтерактивніше, бо «там багато дисків». Перший scrub після запуску — латентність вибухнула. Бази скаржилися. Люди дивилися на графіки ZFS, наче збиралися покаятися.
Припущення було тонке: 12G полиця гарантує 12G на диск і достатній uplink для кількості шпинделів. Насправді в полиці був 12G експандер, але upstream-кабелі були еквівалентом одного x1 lane через поганий вибір кабелю і порт, що знизив швидкість переговорів. Експандер охоче обслужував 24 диски через соломинку.
Підказка була в підозрілому плато throughput: читання scrub застигли на рівні того, що могла дати одна down-negotiated lane. Пер- диск iostat показував багато очікування і низьке використання. Нічого «неправильного» з дисками — просто фабрика була насичена.
Виправлення було нудним: перекомутували на правильний x4 wide link, перевірили negotiated rates і запустили scrub знову. Throughput подвоївся, латентність впала, і команда перестала сперечатися, чи «ZFS потребує RAID-контролера». Також вони занотували мапу портів у рукописному runbook — це не героїчний акт, але необхідний.
Оптимізація, що дала зворотний ефект: крутити всі ручки до 11
Інша компанія мала великий об’єктний стор на ZFS з HDD-vdev за експандерами. Scrub-и були повільні, і хтось вирішив, що це неприйнятно. Вони агресивно підняли concurrency ZFS vdev та підвищили device queue depths бо «більше паралелізму — більше швидкість». Наступний scrub дійсно був швидший — приблизно на п’ятнадцять хвилин.
Потім почалося дивне: API-латентність піднялася, з’явилися тайм-аути, а найзавантаженіші вузли показували осциляції I/O графіків. Це не була проста лінія насичення; виглядало як хвилі заторів і відновлення, як на автомагістралі. Команда відключила scrub, щоб стабілізувати продакшн — саме те, чого робити не можна для цілісності даних.
Післяаналіз показав класичний колапс чергування. Uplink експандера був oversubscribed. Підвищуючи кількість незавершених команд, вони збільшили чергу всередині фабрики і на дисках. Система витрачала більше часу на жонглювання і тайм-аути команд і менше — на корисний I/O. Хвостова латентність роздулася; додатки відчули це відразу.
Виправлення — знизити concurrency scrub/resilver до рівня uplink, тримати помірну глибину черги і планувати scrub-и з явним бюджетом впливу. Результат: scrub тривав довше, ніж «швидка» спроба, але пройшов без порушення продакшну. Це версія, з якою можна жити.
Нудна, але правильна практика, що врятувала день: документація топології і канаркові scrub-и
Одна команда велику підприємства тримала кілька пулів ZFS по багатьох полицях. Вони не були «рухи швидко і ламай сховище». Кожна полиця мала діаграму топології: який порт HBA, який порт експандера, який кабель і які діапазони відсіків належать яким vdev. Це було в електронній таблиці. Це не захопливо. Але це було точно.
Під час вікна обслуговування вони оновили прошивку експандера. Після зміни канарковий scrub на некритичному пулі показав невелике, але постійне падіння throughput і зростання disk_wait. Не катастрофа, але вимірювано. Оскільки у них були «відомі добрі» базові значення з попередніх канаркових scrub-ів, не треба було сперечатися, чи це нормальна варіація.
Вони відкотили прошивку на одній полиці й продуктивність канарки повернулася. Це звузило проблему до специфічної взаємодії прошивки експандера з їхньою моделлю HBA і міксом SATA-дисків. Вони поетапно підбирали іншу версію прошивки і тестували, доки не досягли базової відповідності.
У продакшні нічого драматичного не сталося. Оце й суть. Нудні практики — документація топології, baselines і канаркові scrub-и — перетворюють «таємничі регресії продуктивності» на контрольовані зміни з доказами. Це не гламурно, але краще, ніж відновлення з бекапів.
Типові помилки: симптом → причина → виправлення
1) Scrub-и/resilvers плато на підозріло круглій величині
Симптоми: Throughput зупиняється близько ~550 MB/s, ~1.1 GB/s, ~2.2 GB/s тощо, незважаючи на кількість шпинделів.
Корінь проблеми: Uplink — один lane (або переговори знизились), або wide-porting фактично не працює. Іноді HBA обмежений PCIe.
Виправлення: Підтвердіть negotiated SAS rate і кількість lanes; перекомутуйте на x4 wide port; переконайтесь, що HBA PCIe x8 домовився; розподіліть vdev по uplinks/HBA.
2) Один чи кілька дисків показують величезний await, інші в нормі
Симптоми: iostat -x показує один диск з високим await, низьким throughput і помірним %util; ZFS показує цей leaf-пристрій як відстаючий.
Корінь проблеми: Скиди лінку, переговорене зниження швидкості для цього диска, маргінальний відсік/бекплейн або проблеми phy експандера.
Виправлення: Перевірте dmesg; підтвердіть negotiated speed через SMART; перемістіть диск в інший слот; замініть кабель/бекплейн шлях; оновіть прошивку експандера, якщо це відома проблема.
3) «Multipath увімкнено», але продуктивність незмінна
Симптоми: В ОС є два шляхи, але throughput виглядає як один лінк; failover працює, але масштабування — ні.
Корінь проблеми: Обидва шляхи зливаються в один uplink експандера, або зонування/маршрутизація експандера примушують один активний шлях.
Виправлення: Перевірте фізичну топологію; забезпечте незалежні uplink-и; перевірте зонування/кабельну розкладку експандера і HBA; протестуйте, витягнувши один кабель і дивлячись на зміни шляхів.
4) Пики латентності під час scrub, що зникають після його зупинки
Симптоми: Додатки бачать періодичні тайм-аути; метрики сховища показують піки, корельовані зі сесіями scrub.
Корінь проблеми: Надто висока concurrency scrub для фабрики; арбітраж/oversubscription експандера викликає черги; іноді синхронні навантаження конфліктують.
Виправлення: Зменшіть concurrency scrub/resilver; плануйте scrub-и поза піками; розгляньте special vdev для метаданих; переконайтесь, що uplink-и досить широкі.
5) «Поставили швидший HBA», але нічого не покращилося
Симптоми: Новий SAS3 HBA встановлено; те саме плато; ті ж патерни латентності.
Корінь проблеми: HBA обмежений PCIe lanes, або uplink полиці все ще вузький, або диски SATA за STP домінують поведінкою.
Виправлення: Підтвердіть PCIe x8 на очікуваному поколінні; підтвердіть lanes uplink експандера; розгляньте SAS-диски для важких concurrency-випадків; не забувайте перевірити кабелі.
6) Випадкові таймаути команд під великим навантаженням
Симптоми: У журналах ядра — aborted commands/таймаути; ZFS позначає пристрої як повільні; resilver-и перезапускаються.
Корінь проблеми: Надмірна глибина черги + oversubscription + маргінальні лінки; прошивка експандера з багами; іноді несправності живлення/термальні проблеми викликають нестабільність PHY.
Виправлення: Усунути помилки лінків, знизити concurrency/глибину черги, оновити прошивку, перевірити живлення/термальний режим полиці і перевалідувати стрес-тестами.
Контрольні списки / покроковий план
Крок за кроком: від «сховище повільне» до стабільного виправлення
- Заберіть момент. Збережіть
zpool status,zpool iostat -v -lіiostat -xпід час інциденту. - Перевірте на наявність очевидних проблем одного пристрою. Якщо один диск відстає — спочатку розбирайтеся з ним як з проблемою лінку/пристрою.
- Перевірте журнали на помилки транспорту. Будь-який патерн скидів/повторів переводить у режим апаратного виправлення.
- Підтвердіть переговорені швидкості. Переконайтесь, що диски не застрягли на 3G і uplink-и не вужчі, ніж ви думаєте.
- Підтвердіть переговори PCIe. Переконайтесь, що HBA працює на очікуваній ширині/швидкості.
- Приблизно порахуйте ємність uplink. Lanes × rate; порівняйте з спостереженим плато під scrub.
- Вирішіть: додати пропускну здатність чи зменшити попит. Пропускна здатність: перекомутувати на wide-порти, додати uplink-и, розподілити полиці. Попит: тюнити scrub/resilver concurrency, планувати обслуговування.
- Змініть одну річ. Застосуйте одну корекцію (перекомутування, прошивка, concurrency) і перезаміри.
- Запустіть канарковий scrub. Не весь продакшн спочатку. Перевірте стабільність і вплив на латентність.
- Задокументуйте топологію та базові показники. Якщо пропустите це — заплатите потім з відсотками.
Контрольний список: «Чи дійсно мій uplink експандера широкий?»
- Порти HBA, що використовуються, підтримують wide-porting і налаштовані відповідно.
- Кабелі підтримують очікувану кількість lanes (не всі зовнішні кабелі еквівалентні).
- Переговори лінку на очікуваному рівні (6G/12G) end-to-end.
- OS/драйвер/HBA-утиліта показують кілька phys у wide-порті.
- Немає зонування/маршрутизації, що змушує весь трафік йти одним вузьким шляхом.
Контрольний список: безпечний тюнінг scrub/resilver на oversubscribed полицях
- Починайте консервативно з
zfs.vdev.scrub_max_activeіzfs.vdev.resilver_max_active. - Вимірюйте вплив на латентність продакшну під контролем.
- Збільшуйте маленькими кроками; зупиніться, коли хвостова латентність починає рости.
- Тримайте план відкату (і задокументовані попередні значення).
Питання й відповіді
1) Чи експандери SAS за замовчуванням знижують продуктивність?
Ні. Вони знижують продуктивність, коли ви oversubscribe uplink-и, маєте погане кабелювання/переговори або досягаєте меж справедливості/чергування. При правильних wide-портах і помірній concurrency експандери можуть працювати дуже добре.
2) Чому scrub-и болючіші за звичайні читання?
Scrub-и синхронізовані, стійкі й мають великий фан-аут. Вони тримають багато дисків активними одночасно і виявляють спільні вузькі місця (uplink-и, PCIe, арбітраж), які звичайне прикладне I/O може не зачепити постійно.
3) Чи SATA за SAS-експандером — погана ідея?
Це поширено і може бути прийнятним для шару ємності. Але поведінка STP плюс висока concurrency може давати гіршу хвостову латентність, ніж рідний SAS, особливо під scrub/resilver. Для передбачуваної латентності при високій concurrency простіше працювати з SAS-дисками.
4) Чи варто підвищувати глибину черги, щоб прискорити resilver-и?
Тільки якщо ви довели, що не uplink-bound і латентність стабільна. Якщо ви вже насичуєте uplink експандера, вища глибина черги часто збільшує таймаути і хвостову латентність, роблячи resilver-и менш стабільними.
5) Який є найкращий індикатор вузького місця uplink експандера?
Стабільне плато throughput під час scrub/resilver, що відповідає ємності вузького лінку, плюс підвищені черги/await по багатьох дисках без явного винуватця серед окремих дисків.
6) Як дізнатися, чи wide-porting дійсно працює?
Використайте утиліти HBA, щоб інспектувати phys/порти і negotiated link rates. Лише індикатори на рівні ОС можуть вводити в оману. Також порівняйте throughput під навантаженням: якщо додавання другого кабелю нічого не змінює, ваш «wide port» може бути нешироким.
7) Чи можу я «натюнити ZFS», щоб обійти насичений SAS-uplink?
Ви можете налаштувати ZFS, щоб воно було менш руйнівним (нижча concurrency, кращі політики), але ви не зможете налаштуванням замінити відсутню пропускну здатність. Ви вибираєте між «повільним обслуговуванням» і «повільною всім одночасно». Виправляйте топологію, якщо хочете і швидко, і гладко.
8) Чи допоможе додавання L2ARC або більше RAM при вузьких місцях експандера?
Це може зменшити читання з дисків, що знизить навантаження на фабрику. Це не допоможе записам, які мають потрапити на диски, і не виправить обмеження пропускної здатності scrub/resilver. Розглядайте це як пом’якшення навантаження, а не ремонт транспорту.
9) А розділити пул між кількома експандерами?
Розподіл vdev між незалежними uplink-ами може дати великий виграш. Хитрість у слові «незалежні»: якщо обидва експандери в підсумку проходять через один порт HBA, ви додали лише складності, а не пропускної здатності.
Практичні наступні кроки
Якщо ваш пул ZFS стоїть за SAS-експандером і ви боретесь з повільними scrub-ами, довгими resilver-ами або сплесками латентності, зробіть наступне:
- Підтвердіть negotiated speeds і ширину PCIe. Виправте будь-які зниження переговорів або обмеження lane перед тим, як тюнити щось інше.
- Виміряйте плато і порівняйте з мелемой uplink. Якщо throughput обмежується однією lane або вузьким wide-портом — ви знайшли горлечко.
- Вирівняйте concurrency scrub/resilver під можливості фабрики. Зробіть обслуговування передбачуваним і нешкідливим, навіть якщо воно повільніше, ніж хотілося б.
- Перекомутуйте для пропускної здатності. Wide-порти і кілька uplink-ів перемагають хитрі налаштування sysctl щоразу.
- Занотуйте топологію. Майбутній ви це оцінить, і майбутній ви вже втомився.
Коли фабрика надійна і арифметика лінків відповідає очікуванням, ZFS поводиться як доросла система: нудна, вимірювана та достатньо швидка, щоб усі уникали проблем. Це ідеал. Прагніть до нудного.