Коли референс кращий за кастом: міф, який іноді справджується

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

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

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

Міф: кастом завжди кращий за референс

У цього міфу приємна оповідна арка: ви починаєте з вендорського референсу або upstream-значення, потім «оптимізуєте» його під своє навантаження. Ви видаляєте «баласт». Додаєте хитрий кеш-слой. Переключаєте планувальники I/O. Змінюєте глибину черг. Тюните реплікацію. Графік зміщується праворуч. Ви виграли.

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

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

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

Що насправді означає «референс» (і чого ні)

Референс — це контракт, не порада

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

Вона не ідеальна. Іноді вона консервативна. Іноді вона служить вендору. Іноді вона заморожена у часі, бо служби підтримки бояться хаосу. Але зазвичай вона когерентна. Когерентність недооцінена.

Референс — це не просто «дефолти», а дефолти не завжди рівні референсу

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

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

Референс не знімає з вас відповідальність

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

Чому референс перемагає частіше, ніж інженери визнають

1) Він звужує простір пошуку

Інциденти в продакшні — це проблеми пошуку. Щось не так; потрібно швидко ізолювати причину. Чим більш кастомна ваша система, тим більший простір пошуку і тим менше ваша команда може спертися на відоме хороше поводження. Референсні дизайни зменшують ступені свободи.

В термінах SRE: вони зменшують середній час до невинуватості. Не тому, що вендор завжди правий, а тому, що ви можете швидко виключити цілі класи помилкових конфігурацій.

2) Його тестували під відмовами, а не лише під навантаженням

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

Референси зазвичай налаштовані на поведінку «зріджена, але жива». Кастоми часто налаштовані на «швидко, поки не перестало».

3) Він узгоджується з підтримкою та інструментами

Якщо ви використовуєте комерційний масив зберігання, керовану дистрибуцію Kubernetes або стандартний дистро Linux, ви фактично купуєте екосистему: playbook-и підтримки, відомі баги, рекомендовані прошивки й очікування від інструментів.

Відхилитесь достатньо — і ви відчуєте особливий вид самотності: тикет, у якому підтримка просить відкотитися до референсу перед тим, як вони почнуть розбиратися. Вони не злісні; вони намагаються зробити вашу проблему відтворюваною.

4) Він дає стабільні базові лінії

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

5) Він знижує дрейф конфігурацій

Дрейф — це повільна течія надійності. Кастомні збірки множать ручки, які можуть зсуватися. Навіть якщо ви керуєте ними через ІaC, кожна додаткова ручка створює нове місце для розходжень між середовищами й з часом.

Жарт №1: Якщо ваше тюнінг-сховище вимагає таблиці Excel зі складними макросами, ви не побудували систему — ви побудували тест особистості.

6) Він тримає людину в петлі там, де це потрібно

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

Цитата, бо вона потрібна всім

перефразована ідея — John Ousterhout: простота — передумова для надійності; складність — місце, де полюбляють жити баги й відмови.

Коли кастом повинен перемогти (і як зробити це безпечно)

Кастом перемагає, коли «краще» визначено як вимірювана ціль

«Краще» — не «крутіше». Це не «новіше». Це «p99 записів менше 2 мс при 60% використанні диска», або «відновити том 5 ТБ за 30 хвилин», або «вижити при втраті AZ без ручного втручання».

Якщо ви не можете записати ціль і протестувати її — ви збираєтеся оптимізувати за відчуттями.

Кастом перемагає, коли навантаження дійсно нестандартне

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

Кастом перемагає, коли ви можете дозволити собі операційний податок

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

Кастом перемагає, коли ви можете зробити його знову нудним

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

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

Цікаві факти й історичний контекст

  • Початковий аргумент RAID наприкінці 1980-х був про використання багатьох дешевих дисків надійно; він став референсною базою саме тому, що стандартизував поводження при відмові.
  • TCP congestion control еволюціонував від «тюнінгу на швидкість» до «тюнінгу на справедливість і стабільність» після ранніх колапсів Інтернету; дефолти мають значення, коли всі ділять одну мережу.
  • Бази даних вчилися на практиці, що write-ahead logging і fsync-семантика не підлягають компромісам для коректності; багато «швидких» дизайнів просто пропускали безпеку.
  • Рання адаптація SSD породила хвилю «кастомного» тюнінгу, що ігнорував write amplification і збори сміття прошивки, спричиняючи обриви продуктивності через тижні в продакшні.
  • Віртуалізація нормалізувала overcommit, але також ускладнила розуміння латентності I/O; з’явилися референсні конфіги, щоб контролювати радіус ураження від шумних сусідів.
  • Планувальники I/O в Linux змінювали дефолти з часом, коли сховища перетікали зі шпиндельних дисків до SSD і NVMe; поради з тюнінгу п’ятирічної давнини можуть бути шкідливими тепер.
  • Культура постмортемів в крупних операціях зробила «відтворюваність» вимогою першого рівня; референсні збірки допомагають відтворити стан, який мав значення.
  • Керовані сервіси в хмарі досягли успіху частково тому, що вони прибрали цілі категорії кастомних налаштувань, які користувачі робили неправильно — за дизайном, а не випадково.

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

Міні-історія №1: Інцидент через неправильне припущення

Середня SaaS-компанія вела флот Linux-серверів з локальними NVMe і реплікованою базою даних. Команда отримала у спадок вендорський референс для ОС і файлової системи: консервативні опції монтовання, без екзотичних sysctl і чітка матриця прошивок. Новий інженер помітив «не використану продуктивність» і зробив впевнене припущення: «Це NVMe; бар’єри й порядок не такі важливі, як на шпиндельних дисках».

Вони змінили опції монтування, щоб зменшити синхронний оверхед метаданих, і підлаштували додаток під більшу залежність від page cache ОС. Бенчмарк виглядав фантастично. Графік p95 став гладшим. Деплой святкували тихо, бо інженер не любив уваги. Через тиждень подія живлення вдарила в один стій. Не повний крах — просто грубий відскок.

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

Неправильне припущення було не в тому, що NVMe швидкі. Воно було в тому, що швидкість замінює коректність. Референсні конфіги зазвичай включають консервативні припущення щодо коректності, тому що вендори ризикують судовими позовами, коли дані зникають.

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

Міні-історія №2: Оптимізація, що обернулась проти

Велике підприємство мало платформу Kubernetes з CSI-підтримкою мережевого сховища. Вендор надав референсний лейаут: налаштування multipath, глибини черг і таймаути для відмови. Хтось у платформній команді прочитав стару нитку про тюнінг, де радили збільшити глибину черги для кращої пропускної здатності. Вони підвищили iSCSI queue depth і розміри запитів усьому флоту.

Для пакетних навантажень пропускна здатність покращилася. Графіки виглядали як переможна прогулянка. Потім платформа пережила переключення контролера під час рутинного обслуговування. Це мало бути не подією. Натомість латентність підскочила до секунд. Додатки таймаутили. Поди перезапустилися. On-call отримав пейдж за «випадкову нестабільність сервісів» у кількох неймспейсах.

Постінцидентний аналіз показав, що «оптимізація» заглибила чергу I/O у польоті. Під час переключення ці запити не зникли; вони нагромадилися за транзитну паузу. Час відновлення зростав разом із чергою, тож переключення перетворилося на кількахвилинний браун-аут. Не те, що переключення зламалося — платформна команда зробила переключення дорогим.

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

Міні-історія №3: Нудна, але правильна практика, що врятувала

Фінтех-компанія вела сервіс, що сильно навантажував зберігання, на ZFS під Linux. Їхні інженери мали думки, і ці думки мали власні думки. Проте вони впровадили строгу політику: production-пули мають відповідати перевіреному референсному профілю (recordsize, compression, atime, ashift, sync), а відхилення потребують письмового виправдання плюс плану відкату.

Практика, що здалася найнуднішою, була їхнім щомісячним «аудитом дрейфу референсу». Один інженер порівнював живі налаштування з відомою доброю базою й відкривав невеликі PR для узгодження відмінностей. Це була робота, що ніколи не отримувала оплесків — що зазвичай знак, що вона важлива.

Одного місяця аудит виявив невелику групу вузлів з іншим параметром ядра, пов’язаним із поведінкою запису брудних сторінок. Ніхто не пам’ятав, щоб його змінювали. Симптомів не було — поки що. Команда відкотила зміну й продовжила.

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

Урок: «нудні, але правильні» практики не дають скріншотів перемог. Вони дають ранки, коли ваша кава залишається теплою.

Плейбук швидкої діагностики

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

Перш за все: підтвердьте, що симптом реальний і охоплений

  • Це один хост, одна AZ, один клас зберігання, одне навантаження чи все одразу?
  • Це латентність, пропускна здатність, помилки чи насичення?
  • Щось змінилося: деплой, ядро, прошивка, мережа, feature flag-и?

По-друге: локалізуйте домен вузького місця

  • CPU bound: високий load, високий iowait (обережно), зростання черги виконання, тротлінг.
  • Memory bound: reclaim, свопінг, шторм запису брудних сторінок.
  • Disk/array bound: висока латентність пристрою, насичення черг, вимкнений write cache, рібілди.
  • Network/storage fabric bound: ретрансляції, фліпи лінків, thrash multipath, невідповідність jumbo.
  • Application bound: contention за блокування, синхронні записи, патерни N+1 I/O.

По-третє: вирішіть — відкат чи продовжити дебаг

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

По-четверте: захищайте шляхи відновлення

  • Призупиніть «оптимізації» під час інциденту. Зміни — це те, як ви втрачаєте сюжет.
  • Зберігайте логи й метрики; не перезавантажуйте рефлекторно, якщо це не відновлює сервіс і ви не готові втратити стан.
  • Майте чистий артефакт rollback і відомо-хорошу конфігурацію. Референси корисні лише коли до них можна швидко повернутися.

Практичні завдання: команди, виводи, що це означає, і рішення

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

Завдання 1: Підтвердіть, яке ядро й ОС ви фактично запускаєте

cr0x@server:~$ uname -a
Linux server 6.5.0-21-generic #21~22.04.1-Ubuntu SMP PREEMPT_DYNAMIC x86_64 GNU/Linux

Що це означає: Вашу продуктивність і поведінку I/O сильно залежить від версії ядра й його конфігурації.

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

Завдання 2: Ідентифікуйте параметри завантаження й приховані sysctl

cr0x@server:~$ cat /proc/cmdline
BOOT_IMAGE=/vmlinuz-6.5.0-21-generic root=UUID=... ro quiet splash transparent_hugepage=never

Що це означає: Деякі «дрібні» boot-параметри можуть домінувати над латентністю (THP, mitigations, IOMMU-настройки).

Рішення: Якщо ваш флот неконсистентний з референсом, стандартизуйте. Дрейф тут породжує привидів у логах.

Завдання 3: Перевірте опції монтування файлової системи (компроміс надійність ↔ швидкість)

cr0x@server:~$ findmnt -no TARGET,SOURCE,FSTYPE,OPTIONS /var/lib/data
/var/lib/data /dev/nvme0n1p2 ext4 rw,relatime,errors=remount-ro

Що це означає: Опції монтування показують, чи хтось відключив функції безпеки або ввімкнув екзотику.

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

Завдання 4: Швидко перевірте стан диска перед тим, як звинувачувати тюнінг

cr0x@server:~$ sudo smartctl -a /dev/nvme0n1 | sed -n '1,25p'
smartctl 7.2 2020-12-30 r5155 [x86_64-linux-6.5.0-21-generic] (local build)
=== START OF INFORMATION SECTION ===
Model Number:                       ACME NVMe 3.2TB
Firmware Version:                   1.4.9
Percentage Used:                    74%
Data Units Written:                 987,654,321
Media and Data Integrity Errors:    0

Що це означає: «Percentage Used» близько до кінця життєвого циклу й невідповідність версій прошивок можуть створювати сплески латентності.

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

Завдання 5: Подивіться реальну латентність пристрою й черги

cr0x@server:~$ iostat -x 1 3
Linux 6.5.0-21-generic (server) 	01/21/2026 	_x86_64_	(32 CPU)

avg-cpu:  %user   %nice %system %iowait  %steal   %idle
          12.30    0.00    4.10    8.20    0.00   75.40

Device            r/s   w/s  rMB/s  wMB/s  avgrq-sz avgqu-sz await r_await w_await  svctm  %util
nvme0n1         1200  1800   95.0  210.0      180     12.5   6.8    3.1     9.2   0.25  97.0

Що це означає: Високий await і високий %util вказують на насичення пристрою або upstream-чергування.

Рішення: Якщо пристрій завантажений, допомогти може тюнінг concurency у додатку або розподіл навантаження. Якщо це спільний масив — перевіряйте fabric і здоров’я масиву; не просто підвищуйте глибину черг.

Завдання 6: Ідентифікуйте I/O scheduler і чи відповідає він носію

cr0x@server:~$ cat /sys/block/nvme0n1/queue/scheduler
[none] mq-deadline kyber bfq

Що це означає: NVMe часто працює добре з none, але ваше навантаження може віддавати перевагу планувальнику для справедливості.

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

Завдання 7: Перевірте writeback і налаштування брудних сторінок (класична «підставка»)

cr0x@server:~$ sysctl vm.dirty_background_ratio vm.dirty_ratio vm.dirty_expire_centisecs
vm.dirty_background_ratio = 10
vm.dirty_ratio = 20
vm.dirty_expire_centisecs = 3000

Що це означає: Агресивні налаштування dirty можуть створювати періодичні шторм-флаши й хвостові сплески латентності.

Рішення: Якщо кастомне значення введено для «підвищення пропускної здатності», перевірте хвостову латентність. Для чутливих до латентності систем тримайте консервативні дефолти, якщо не можете протестувати під відмовами й сплесками.

Завдання 8: Перевірте, чи відбувається свопінг (розв’язка «таємничої» продуктивності)

cr0x@server:~$ free -h
               total        used        free      shared  buff/cache   available
Mem:           125Gi        92Gi        4.1Gi       1.2Gi        29Gi        21Gi
Swap:           16Gi       5.3Gi        11Gi

Що це означає: Використання swap може перетворити сховище на генератор випадкової латентності.

Рішення: Якщо свопінг суттєвий у сервісі, чутливому до латентності — виправляйте пам’ять першочергово. Не тюньте сховище, щоб компенсувати нестачу RAM.

Завдання 9: Виловіть помилки зберігання, що маскуються під «проблеми продуктивності»

cr0x@server:~$ sudo dmesg -T | egrep -i "blk_update_request|nvme|scsi|reset|timeout|I/O error" | tail -n 8
[Tue Jan 21 09:44:12 2026] nvme nvme0: I/O 123 QID 4 timeout, aborting
[Tue Jan 21 09:44:12 2026] nvme nvme0: Abort status: 0x371
[Tue Jan 21 09:44:14 2026] nvme0n1: I/O Cmd(0x2) @ LBA 0x3c1a0, 8 blocks, I/O Error (sct 0x2 / sc 0x81)

Що це означає: Тайм-аути й аборти часто спочатку проявляються як сплески латентності, а потім як помилки.

Рішення: Припиніть тюнінг. Ескалюйте апаратне/прошивкове дослідження, порівняйте з референсною прошивкою й розгляньте проактивну заміну.

Завдання 10: Перевірте стан multipath (для SAN/iSCSI/FC)

cr0x@server:~$ sudo multipath -ll | sed -n '1,25p'
mpatha (3600508b400105e210000900000490000) dm-2 ACME,UltraSAN
size=2.0T features='1 queue_if_no_path' hwhandler='0' wp=rw
|-+- policy='service-time 0' prio=50 status=active
| `- 3:0:0:1 sdb 8:16 active ready running
`-+- policy='service-time 0' prio=10 status=enabled
  `- 4:0:0:1 sdc 8:32 active ready running

Що це означає: Якщо шляхи фліпають, ви побачите непередбачувану латентність і ретраї.

Рішення: Якщо політики multipath відрізняються від референсу — відкотіть. Якщо шлях впав, спочатку виправляйте кабелі/комутатор/HBA хоста, а не чіпайте ручки додатка.

Завдання 11: Виміряйте латентність на рівні файлової системи на вимогу

cr0x@server:~$ sudo ioping -c 10 -D /var/lib/data
4 KiB from /var/lib/data (ext4 /dev/nvme0n1p2): request=1 time=0.42 ms
4 KiB from /var/lib/data (ext4 /dev/nvme0n1p2): request=2 time=0.51 ms
...
--- /var/lib/data (ext4 /dev/nvme0n1p2) ioping statistics ---
10 requests completed in 9.01 s, 40 KiB read, 1.11 KiB/s
min/avg/max/mdev = 0.39 ms / 0.58 ms / 1.21 ms / 0.23 ms

Що це означає: Це дає швидку перевірку «чи зараз сховище повільне?» на рівні файлової системи.

Рішення: Якщо ioping показує високу латентність, а стати пристроїв виглядають нормально — підозрюйте contention у файловій системі, cgroup-обмеження I/O або проблеми з бекендом мережевого сховища.

Завдання 12: Перевірте реальний патерн I/O контролюваним бенчмарком (обережно)

cr0x@server:~$ sudo fio --name=randread --directory=/var/lib/data --rw=randread --bs=4k --iodepth=32 --numjobs=4 --size=2G --runtime=30 --time_based --group_reporting
randread: (g=0): rw=randread, bs=(R) 4096B-4096B, (W) 4096B-4096B, ioengine=psync, iodepth=32
...
  read: IOPS=185k, BW=723MiB/s (758MB/s)(21.2GiB/30001msec)
    lat (usec): min=68, max=24890, avg=512.20, stdev=301.44
    clat percentiles (usec):
     |  1.00th=[  95], 50.00th=[ 480], 95.00th=[ 910], 99.00th=[1400], 99.90th=[3900]

Що це означає: Ви отримуєте IOPS і перцентилі латентності, а не лише середню швидкість. Перцентилі — це те, де живе продакшн.

Рішення: Якщо ваш кастом покращує середнє, але погіршує p99/p99.9 — це зазвичай програш. Тримайте референс, якщо тільки ви не будуєте для пакетної пропускної здатності.

Завдання 13: Перевірте помилки NIC і ретрансляції (мережеве сховище любить це)

cr0x@server:~$ ip -s link show dev eth0 | sed -n '1,12p'
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP mode DEFAULT group default qlen 1000
    RX:  bytes packets errors dropped  missed   mcast
    9876543210  1234567      0     12       0  12345
    TX:  bytes packets errors dropped carrier collsns
    8765432109  2345678      0      0       0       0

Що це означає: Дропи на RX можуть прямо перетворюватись на латентність сховища на NFS/iSCSI/Ceph публічних мережах.

Рішення: Якщо лічильники дропів зростають — перестаньте звинувачувати «тюнінг сховища». Перевірте узгодженість MTU, буфери комутаторів і qdisc на хості — віддавайте перевагу референсній мережевій конфігурації.

Завдання 14: Виявити тротлінг CPU або %steal у віртуалізованих середовищах

cr0x@server:~$ mpstat -P ALL 1 2 | sed -n '1,18p'
Linux 6.5.0-21-generic (server) 	01/21/2026 	_x86_64_	(32 CPU)

12:03:21 PM  CPU   %usr  %nice   %sys %iowait  %irq  %soft  %steal  %idle
12:03:22 PM  all  14.22   0.00   4.55    7.91  0.00   0.28    3.40  69.64

Що це означає: %steal свідчить, що вашій VM не дають CPU; латентність сховища може бути симптомом, а не причиною.

Рішення: Якщо steal немалий — дослідіть конкуренцію на хості або перемістіть навантаження. Не тюньте сховище щоб вирішити проблему планувальника.

Завдання 15: Перевірте стан пулу ZFS (якщо ви використовуєте ZFS)

cr0x@server:~$ sudo zpool status -v
  pool: tank
 state: ONLINE
  scan: scrub repaired 0B in 00:12:31 with 0 errors on Tue Jan 21 02:00:10 2026
config:

        NAME        STATE     READ WRITE CKSUM
        tank        ONLINE       0     0     0
          raidz1-0  ONLINE       0     0     0
            sda     ONLINE       0     0     0
            sdb     ONLINE       0     0     0
            sdc     ONLINE       0     0     0

errors: No known data errors

Що це означає: Scrub-и, помилки й дегрейджені vdev-и важать більше, ніж будь-який «хак recordsize».

Рішення: Якщо бачите помилки або дегрейдж — віддайте пріоритет цілісності даних і плануванню рібілду над тюнінгом продуктивності.

Завдання 16: Перевірте налаштування dataset-ів ZFS, які часто «погано кастомізують»

cr0x@server:~$ sudo zfs get -o name,property,value -s local,received compression,recordsize,atime,sync tank/app
NAME      PROPERTY    VALUE
tank/app  compression zstd
tank/app  recordsize  128K
tank/app  atime       off
tank/app  sync        standard

Що це означає: Ці властивості змінюють write amplification, латентність і семантику надійності.

Рішення: Якщо sync=disabled з’явився в продакшні без ясного обґрунтування й гарантій UPS/PLP — розглядайте це як інцидент і відкотіть до референсу.

Жарт №2: «Ми підганяли для пікової продуктивності» — це як інженери кажуть «ми підганяли для пікової несподіванки».

Поширені помилки: симптом → корінна причина → виправлення

1) Симптом: Чудова середня пропускна здатність, жахлива p99 латентність

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

Виправлення: Зменшіть конкуренцію до шару зберігання, відновіть референсні глибини черг, впровадьте SLO для латентності й тестуйте змішані read/write з фоновими задачами.

2) Симптом: Випадкові багатосекундні паузи під час «нормальної» роботи

Корінна причина: Шторми флашу брудних сторінок, contention журналу файлової системи або фонова рібілд/скраб-операція, що конфліктує з піковим навантаженням.

Виправлення: Тюньте writeback консервативно, плануйте вікна обслуговування й вимірюйте вплив scrub/rebuild. Якщо в референсі є поради щодо планування — дотримуйтесь їх.

3) Симптом: Сховище виглядає нормально, але додатки таймаутять

Корінна причина: Мережеві дропи/ретрансляції, затримки DNS, %steal CPU або contention на рівні додатку, що маскується під I/O.

Виправлення: Перевірте iostat + ip stats + mpstat; не припускайте. Зробіть правило «доведіть, що це сховище», перш ніж змінювати налаштування сховища.

4) Симптом: Після failover або link flap все тане на хвилини

Корінна причина: Надмірні in-flight I/O через агресивне чергування; таймаути й поведінка ретраїв не погоджені з референсом.

Виправлення: Відновіть референсні multipath і таймаути; проведіть контрольований тест failover, щоб виміряти час браун-ауту. Оптимізуйте під відновлення, а не лише під steady-state швидкість.

5) Симптом: Продуктивність погіршується протягом тижнів на SSD/NVMe

Корінна причина: Зношування, поведінка GC прошивки, відсутність стратегії TRIM/discard або переповнення дисків.

Виправлення: Тримайте запас вільного простору, узгоджуйте прошивку з референсом, валідуйте стратегію discard і відстежуйте латентність із віком дисків.

6) Симптом: «Воно було швидким у staging» стало рефреном

Корінна причина: Staging не містить продакшн-конкуренції, режимів відмов і фонових задач. Кастомний тюнінг валідували в іграшковому світі.

Виправлення: Створіть продакшн-подібний load-test, включіть бекапи/рібілди й вимірюйте p99. Якщо не можете — тримайтесь близько до референсу.

7) Симптом: Підтримка відмовляється допомагати або просить ще логи

Корінна причина: Ви відхилились від підтримуваного референсу (драйвери, прошивка, налаштування), тож вашу проблему неможливо відтворити в їхній лабораторії.

Виправлення: Узгодьтеся з референсною матрицею; документуйте будь-яке відхилення і як ви його валідували.

8) Симптом: «Ми оптимізували» і оновлення стали страшними

Корінна причина: Кастомні ручки тісно зв’язані з конкретною поведінкою ядра/прошивки; немає суміснісного конверту.

Виправлення: Зменшіть площу кастому, закодуйте конфіг у IaC, додайте canary-оновлення й тримайте відомо-хороший артефакт для відкату.

Чеклісти / покроковий план

Чекліст A: Вирішити, чи залишатися на референсі

  1. Запишіть ціль. Латентність? Пропускна здатність? Вартість? Час відновлення? Будьте точні.
  2. Перелічіть обмеження. Цілісність даних, відповідність, підтримуваність, рівень навичок on-call.
  3. Виміряйте базу на референсі. Зафіксуйте p50/p95/p99 латентність і точки насичення.
  4. Інвентаризуйте дрейф. Ядро, прошивка, sysctl-и, опції монтовання, драйвери, налаштування multipath.
  5. Оцініть операційний податок. Додаткові дашборди, runbook-и, тести, навчання, ризик оновлень.
  6. Рішення: копіювати чи форкати. Якщо не можете профінансувати податок — не форкайте.

Чекліст B: Якщо все ж кастомізувати — робіть це по-діловому

  1. Одна зміна за раз. Ставте кожне відхилення як експеримент з можливістю відкату.
  2. Визначте обмеження. Макс прийнятний p99, макс браун-aут під час failover, макс час рібілду.
  3. Тестуйте режими відмов. Переключення контролера, фліп лінку, видалення диска, ребут ноди під навантаженням.
  4. Канарка в продакшні. Малий blast-radius, швидкий шлях відкату, щільний моніторинг.
  5. Документуйте чому. «Ми змінили X, бо метрика Y падала, і Z доводить покращення.»
  6. Репетируйте відкат. Якщо відкат потребує зборів — це не відкат.

Чекліст C: Тримати референс «референсом» з часом

  1. Зафіксуйте артефакт референсу. Шлях у репо, бандл конфігів, підписаний голден-образ.
  2. Аудит дрейфу щомісяця. Порівнюйте живі налаштування з базою автоматично.
  3. Відстежуйте прошивки як код. Трактуйте оновлення прошивки як деплої, з канарками.
  4. Тримайте нотатки з оновлень. Зміни ядра й стеку зберігання мають відслідковуватись як релізи додатка.
  5. Видаляйте фольклор. Якщо ручка тюнінгу не обґрунтована поточними даними — видаляйте її.

Питання й відповіді

1) Чи референсна архітектура завжди повільніша?

Ні. Вона часто «достатньо швидка» й стабільна під навантаженням і відмовами. Багато кастомів виграють у синтетичних тестах, а потім програють хвостовій латентності й поведінці відновлення в продакшні.

2) Чому вендори радять консервативні дефолти?

Бо вендорів звинувачують у втраті даних і нестабільності. Консервативні дефолти зазвичай захищають коректність, сумісність і підтримуваність для найбільш широкого набору помилок клієнтів.

3) Якщо в мене дуже специфічне навантаження, чи не варто його тюнити?

Варто, але ставтесь до тюнінгу як до інженерії: вимірюйте, ізолюйте змінні, валідируйте режими відмов і закладайте операційний податок. «Специфічне навантаження» — це не ліцензія робити на око.

4) Як зрозуміти, чи я відхилився від референсу?

Порівняйте версії ядра, прошивки, sysctl-и, опції монтування, політики multipath і версії драйверів зі базою. Якщо не можете їх перелічити — ви вже відхилились.

5) Який найбільший червоний прапор у кастомному тюнінгу сховища?

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

6) Ми не можемо відтворити продакшн-продуктивність у staging. Що робити?

Припустіть, що staging брешуть. Використовуйте production-канарки, збирайте детальні перцентилі латентності і тестуйте під реалістичною фоновою активністю. Тримайтеся референсу, поки не зможете безпечно виміряти.

7) Чи референсні конфіги захищені від аутеджів?

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

8) Скільки кастомізації — це «занадто»?

Коли команда більше не може пояснити поведінку при відмовах або відновити систему надійно. Хороший індикатор — коли оновлення вимагають героя і вихідних.

9) Що робити, якщо референс не підходить для нашого заліза?

Тоді ваш перший крок — узгодити апаратуру/прошивку з валідаційною матрицею або вибрати референс, що відповідає вашій платформі. Не «тюньте навколо» несумісних компонентів.

10) Чи можна змішувати референс і кастом?

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

Висновок: наступні кроки, які ви реально можете зробити

Міф не в тому, що кастом може перемогти референс. Міф у тому, що кастом автоматично кращий і що перемога — лише технічна. У продакшні продуктивність — це політика між навантаженням, залізом, ядром, мережею і людьми на виклику.

Якщо ви вирішуєте, чи кастомізувати — зробіть цього тижня три речі:

  1. Запишіть вашу референсну базу (ядро, прошивка, sysctl-и, опції монтування, налаштування зберігання) і збережіть її як артефакт, який команда може порівнювати.
  2. Пройдіть кроки швидкої діагностики у звичайний день і зафіксуйте «нормальні» числа: iostat латентність, дропи, здоров’я multipath, використання swap, p99 від fio на канарковому боксі.
  3. Виберіть одне відхилення, яке ви зараз використовуєте, і змусьте його захищати себе: яку метрику він покращує, який режим відмов погіршує, і як ви його відкотите о 3 ранку.

Якщо відхилення не може себе захистити — видаліть його. Найнадійніші системи не ті, що мають найбільше тюнінгу. Вони ті, що мають найменше сюрпризів.

← Попередня
Ubuntu 24.04 APT повільний: кеш/проксі хитрощі, що пришвидшують офісні оновлення
Наступна →
Виявлення невідповідності ashift у ZFS: як перевірити існуючі пули

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