Спадкова магія: ніхто не знає, як це працює — не чіпайте

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

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

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

Що насправді таке «спадкова магія»

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

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

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

Чому вона виживає (і чому ламається)

Спадкова магія виживає, бо колись була найкращим варіантом

Більшість «таємних» стеків не були створені некомпетентними людьми. Їх робили люди під тиском, з обмеженими інструментами
і часто з апаратними обмеженнями, які вимагали винахідливості. Якщо ви досить молоді, щоб завжди мати дешеві SSD і керовані
бази даних, ви живете у розкоші. Старі системи мусили вичавлювати продуктивність з обертових дисків, малої RAM, повільних мереж
і іноді бюджету, що виглядав як помилка друку.

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

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

Системи не вмирають від старості. Вони помирають від зміщення інтерфейсів: бібліотеки змінюють поведінку, вимоги TLS ужорсточуються,
DNS або NTP‑проблеми посилюються жорсткими перевірками часу, віртуалізоване сховище поводиться інакше, ніж локальні диски,
а ваш новий «швидший» тип інстансу має зовсім іншу топологію CPU. Тоді система, яка працювала роками, руйнується за тиждень.

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

Факти та історичний контекст, якими можна скористатися

  • «Write once, run anywhere» мала тінь: рання портативність часто приховувала припущення про продуктивність, особливо щодо семантики файлових систем і обробки часу.
  • POSIX файлові системи не були створені для вашого мікросервісного рою: багато спадкових додатків припускають локальні, малолатентні, сильноконсистентні файлові операції.
  • NFS став стандартним клеєм в організаціях: він також унормував «іноді повільно» як операційну реальність — багато додатків тихо написали обхідні шляхи під це.
  • RAID контролери формували налаштування БД: старе тонке налаштування БД часто припускало батарейно‑захищений кеш запису; прибрати його — і ваша «стабільна» система стає машиною затримок.
  • VM змінювали час: дрейф годинника і джитер планування у віртуалізованих середовищах ламали старе ПО, яке припускало монотонний час або передбачувані таймери.
  • Логи раніше були стеком спостережуваності: багато «магії» покладається на парсинг логів або ad‑hoc grep‑пілайн, про які ніхто не зізнається, що вони критичні для продакшну.
  • Init‑скрипти були операційною логікою: до systemd багато організацій вплітали крихкий порядок ініціалізації в кастомні init‑скрипти.
  • Бар’єри файлової системи і порядок записів еволюціонував: перемикачі на кшталт write barriers змінювали компроміси безпеки/продуктивності, і стара порада може бути зараз шкідливою.
  • «Batch windows» були проєктною примітивою: нічна обробка формувала моделі даних, стратегії блокувань і плани бекапів; постійно‑доступні навантаження навантажують їх по‑іншому.

Операційні правила: як торкатися безпечно

Правило 1: Ставтеся до «невідомого» як до залежності, а не як до сорому

Таємниця — це не моральна невдача. Це стан системи. Ваше завдання — зменшити таємницю так само, як зменшують латентність: вимірюючи,
ізолюючи та ітеруючи. Якщо культура команди трактує незнання як стид, люди приховуватимуть невизначеність — і ви підштовхнете ризик.

Правило 2: Не міняйте поведінку, поки не зможете її спостерігати

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

Є цитата, яку операційники постійно заново відкривають, бо вона завжди правда: «Ви не можете покращити те, що не вимірюєте.» — Peter Drucker (парафраз).
Вимірювання не зроблять систему безпечною, але вони зроблять зміни перевірюваними.

Правило 3: Зменшуйте радіус ураження перед тим, як покращувати продуктивність

Робота з продуктивністю спокуслива: бачите сплеск на графіку — хочете виправити. Але «фікси» продуктивності у спадкових систем часто залежать від obscure порядку,
механізмів backpressure або таймінгу. Спочатку зробіть наслідки меншими: канаркові зміни, feature‑flags, коротші вікна обслуговування,
менші набори даних, менші області реплікації. Потім оптимізуйте.

Правило 4: Віддавайте перевагу оборотним змінам

Якщо ваша зміна не повертається швидко, її треба тестувати як хірургічну імплантацію. У спадковому середовищі рідко є такий розкіш.
Обирайте зміни, які можна вимкнути: конфіг‑флаги, runtime‑параметри, read‑only probes, shadow‑трафік, паралельні конвеєри.

Правило 5: Відокремлюйте «як це працює» від «як це ламається»

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

Жарт №1: Спадкові системи як чавунні сковорідки — якщо занадто сильно її почистити, «приправа» зійде і всі обуряться.

Правило 6: Документуйте намір, а не дрібниці

«Set vm.dirty_ratio=12» — це дрібниця. «Тримати writeback latency нижче X, щоб DB checkpoint не зависав» — це намір.
Друге переживе зміну обладнання і оновлення ядра. Намір дозволяє наступному інженеру зробити інший, але правильний вибір.

Правило 7: Сховище зазвичай тихий співучасник

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

Правило 8: «Не чіпайте» — це пункт реєстру ризиків, а не стратегія

Якщо система занадто страшна для змін, надто ризиковано на неї покладатися. Внесіть її до реєстру ризиків із конкретними тригерами:
закінчення терміну сертифіката, end‑of‑life ОС, припинення продажу моделі диска, оновлення контракту постачальника, втрата ключової людини.
Потім складіть план, який заміняє страх конкретними кроками.

Швидкий плейбук діагностики

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

Перший крок: підтвердіть вплив і обмежте радіус ураження

  • Це затримка для користувача, пропускна здатність, рівень помилок чи коректність даних?
  • Це один хост, одна AZ, один шард, один орендар чи глобально?
  • Чи щось змінювалося за останню годину/день: деплой, конфіг, ядро, шлях зберігання, мережеві ACL, оновлення сертифікатів?

Другий крок: вирішіть, чи ви обмежені CPU, пам’яттю або I/O

  • CPU‑bound: велика черга виконання, високий user/system CPU, низький I/O wait, стабільна латентність до насичення.
  • Memory‑bound: зростання major faults, активність swap, затримки reclaim, OOM‑kill, thrash кешу.
  • I/O‑bound: високий iowait, висока зайнятість диска, великі await/service times, заблоковані потоки, fsync‑шторм.

Третій крок: перевірте насичення і черги на найнижчому шарі

  • Сховище: глибина черги пристрою, латентність, помилки, multipath failover, повна файловая система, ZFS pool health, md RAID resync.
  • Мережа: ретрансмісії, дропи, MTU‑несумісність, проблеми дуплексу, затримки DNS, сплески TLS‑handshake.
  • Ядро: попередження в dmesg, завислі задачі, soft lockups, timeouts блокового шару.

Четвертий крок: ідентифікуйте процес‑вузьке місце та його залежність

  • Який PID споживає CPU, блокується на I/O або утримує локи?
  • На які файли, сокети чи диски він очікує?
  • Чи контенція внутрішня (локи), чи зовнішня (сховище/мережа)?

П’ятий крок: застосуйте найменше безпечне пом’якшення

  • Обмежте швидкість шумних job‑ів (cron, batch, compactions).
  • Переключіть читання, зніміть трафік або перерозподіліть навантаження.
  • Збільшіть запас (тимчасова ємність, кеш або налаштування черги) тільки якщо ви розумієте побічні ефекти.

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

Це базові кроки, коли ви маєте справу з таємничим сервісом на Linux зі сховищем у грі.
Кожне завдання включає команду, зразок виводу, що він означає, і рішення, яке з цього випливає.
Спочатку запускати у режимі тільки читання. Допитливість — добре; несподівані перезавантаження — ні.

Завдання 1: Знайти останні зміни (стан пакетів і сервісів)

cr0x@server:~$ journalctl --since "6 hours ago" -p warning..alert | tail -n 20
Jan 12 10:14:03 app01 kernel: nvme nvme0: I/O 123 QID 4 timeout, aborting
Jan 12 10:14:03 app01 kernel: blk_update_request: I/O error, dev nvme0n1, sector 987654 op 0x1:(WRITE) flags 0x0 phys_seg 16 prio class 0
Jan 12 10:18:11 app01 systemd[1]: myapp.service: Main process exited, code=killed, status=9/KILL

Значення: таймаути I/O ядра плюс помилки, потім сервіс було вбито. Це не «додаток став повільним». Це — «сховище горить».

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

Завдання 2: Отримати одноекранний огляд здоров’я (CPU, пам’ять, load, iowait)

cr0x@server:~$ vmstat 1 5
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 2  0      0  81232  41200 621000    0    0   120   210  950 1400 12  6 78  4  0
 4  1      0  50440  39800 612400    0    0   110   980 1100 2100 10  7 55 28  0
 6  3      0  49600  39000 610800    0    0    90  1600 1200 2600  8  6 40 46  0

Значення: зростаючий b (blocked) і wa (iowait) вказують на потоки, що чекають на I/O.

Рішення: переключіться на перевірки диска і файлової системи; не «просто додавайте CPU». CPU ще не вузьке місце.

Завдання 3: Визначити, які диски повільні і як саме (латентність проти завантаження)

cr0x@server:~$ iostat -xz 1 3
avg-cpu:  %user   %nice %system %iowait  %steal   %idle
           9.21    0.00    6.14   31.55    0.00   53.10

Device            r/s     w/s   rkB/s   wkB/s  rrqm/s  wrqm/s  %util  await  svctm
nvme0n1         220.0  310.0  9024.0 12800.0     0.0     0.0   99.5  18.2   0.9
nvme1n1          10.0   12.0   400.0   520.0     0.0     0.0    3.1   1.2   0.2

Значення: %util близько 100% із високим await означає, що пристрій насичений і запити чергуються.

Рішення: знайдіть, що б’є по nvme0n1 і зменшіть швидкість запису, перемістіть «гарячі» дані або додайте ємності/IOPS. Якщо це мало би бути «дзеркаловано», перевірте, чи це справді так.

Завдання 4: Знайти процес, що генерує I/O

cr0x@server:~$ sudo iotop -o -b -n 3
Total DISK READ: 8.12 M/s | Total DISK WRITE: 45.33 M/s
  PID  PRIO  USER     DISK READ  DISK WRITE  SWAPIN  IO>    COMMAND
 7321 be/4   myapp     1.23 M/s  22.10 M/s   0.00 %  6.12 % myapp --worker
 9012 be/4   postgres  0.00 B/s  18.44 M/s   0.00 %  5.90 % postgres: checkpointer

Значення: додаток і Postgres checkpointer — великі записувачі. Така комбінація часто означає, що брудні сторінки скидаються хвилями.

Рішення: розгляньте згладжування записів (налаштування checkpoint у БД) і перевірте, чи не змінилася латентність сховища нещодавно. Не вбивайте checkpointer нахрапом; він займається контрольним відновленням.

Завдання 5: Перевірити наповненість файлової системи та виснаження inode (тупа відмова)

cr0x@server:~$ df -hT
Filesystem     Type  Size  Used Avail Use% Mounted on
/dev/nvme0n1p2 ext4  200G  196G  2.1G  99% /
/dev/nvme1n1p1 ext4  500G  120G  356G  26% /data

Значення: root‑файлова система на 99%. Очікуйте дивностей: тимчасові файли не створюються, логи не пишуться, сервіси падають непрозорими помилками.

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

Завдання 6: Перевірити доступність inode (малі файли можуть вас вбити)

cr0x@server:~$ df -i
Filesystem      Inodes  IUsed   IFree IUse% Mounted on
/dev/nvme0n1p2 1310720 1310100     620  100% /
/dev/nvme1n1p1 3276800  210000 3066800    7% /data

Значення: 100% використання inode: у вас може бути «вільне місце», але ви не можете створити файли. Спадкові batch‑системи люблять створювати дрібні файли.

Рішення: знайдіть директорію з вибухом (зазвичай логи, spool, temp, cache). Очистіть і додайте запобіжники (logrotate, політики зберігання).

Завдання 7: Ідентифікувати опції монтування і ризикові поведінки (barriers, noatime тощо)

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

Значення: relatime — нормально; errors=remount-ro означає, що при помилках файлову систему переведуть у режим тільки для читання, що може виглядати як «зависання додатка».

Рішення: якщо ви бачили помилки I/O, плануйте можливий flip у read‑only і забезпечте коректну обробку сервісами. У спадкових системах часто цього немає.

Завдання 8: Перевірити ядро на завислі задачі і проблеми блочного шару

cr0x@server:~$ dmesg -T | tail -n 30
[Sun Jan 12 10:14:03 2026] nvme nvme0: I/O 123 QID 4 timeout, aborting
[Sun Jan 12 10:14:09 2026] INFO: task myapp:7321 blocked for more than 120 seconds.
[Sun Jan 12 10:14:09 2026]       Tainted: G        W  OE     5.15.0-91-generic #101-Ubuntu
[Sun Jan 12 10:14:09 2026] Call Trace:
[Sun Jan 12 10:14:09 2026]  __schedule+0x2c5/0x6f0
[Sun Jan 12 10:14:09 2026]  io_schedule+0x46/0x70

Значення: задачі заблоковані в плануванні I/O: класичний симптом затримок сховища.

Рішення: ескалюйте на рівень зберігання: перевірте SMART/NVMe логи пристрою, контролер, multipath, SAN і недавні оновлення прошивки.

Завдання 9: Зіставити «гарячі» файли з пристроями (яке монтування винне)

cr0x@server:~$ sudo lsof -p 7321 | head -n 10
COMMAND  PID USER   FD   TYPE DEVICE SIZE/OFF     NODE NAME
myapp   7321 myapp  cwd    DIR  259,2     4096  131073 /
myapp   7321 myapp  10w   REG  259,2  1048576  262200 /var/log/myapp/worker.log
myapp   7321 myapp  11w   REG  259,2  5242880  262199 /var/lib/myapp/spool/events.dat

Значення: процес записує під /var на root‑диску (DEVICE 259,2), а не на /data. Це може бути випадково й катастрофічно.

Рішення: перемістіть спул/логи на відповідний data‑том, бажано через симлінк або bind‑mount для мінімальних змін. Спочатку перевірте, чи ніщо не залежить від попереднього шляху.

Завдання 10: Перевірити цикли перезапуску сервісів і порядок залежностей

cr0x@server:~$ systemctl status myapp.service --no-pager
● myapp.service - MyApp Worker
     Loaded: loaded (/etc/systemd/system/myapp.service; enabled; vendor preset: enabled)
     Active: activating (auto-restart) (Result: exit-code) since Sun 2026-01-12 10:18:12 UTC; 6s ago
    Process: 9441 ExecStart=/usr/local/bin/myapp --worker (code=exited, status=1/FAILURE)
   Main PID: 9441 (code=exited, status=1/FAILURE)
        CPU: 210ms

Jan 12 10:18:12 app01 myapp[9441]: FATAL: cannot create /var/lib/myapp/spool/lock: No space left on device

Значення: вже не загадка: падіння через брак простору, а systemd б’є рестартами.

Рішення: зупиніть цикл рестартів, якщо він погіршує I/O (тимчасово systemctl stop), звільніть місце, потім перезапустіть. Додайте моніторинг/алерти на диск/іноди, щоб уникнути повтору.

Завдання 11: Перевірити cron/system timers (невидиме навантаження)

cr0x@server:~$ systemctl list-timers --all --no-pager | head -n 12
NEXT                        LEFT     LAST                        PASSED   UNIT                         ACTIVATES
Sun 2026-01-12 10:30:00 UTC 7min left Sun 2026-01-12 10:00:00 UTC 23min ago logrotate.timer              logrotate.service
Sun 2026-01-12 11:00:00 UTC 37min left Sun 2026-01-12 10:00:03 UTC 23min ago fstrim.timer                fstrim.service
Sun 2026-01-12 12:00:00 UTC 1h 37min Sun 2026-01-12 00:00:00 UTC 10h ago    apt-daily-upgrade.timer      apt-daily-upgrade.service

Значення: fstrim на тонко‑провізіонованому або зайнятому сховищі може спричиняти сплески латентності; logrotate може викликати хвилі rename/compress I/O.

Рішення: якщо spikes корелюють, перенесіть таймери в вікна низької навантаженості або відтоньте їх (наприклад, частоту trim). Перед зміною валідуйте метриками.

Завдання 12: Мережева перевірка для «сховища», яке насправді віддалене

cr0x@server:~$ ip -s link show dev eth0 | sed -n '1,12p'
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP mode DEFAULT group default qlen 1000
    link/ether 52:54:00:ab:cd:ef brd ff:ff:ff:ff:ff:ff
    RX:  bytes packets errors dropped  missed   mcast
    987654321  1234567      0    1241       0       0
    TX:  bytes packets errors dropped carrier collsns
    123456789  2345678      0       0       0       0

Значення: RX‑дропи: можуть спричиняти біль NFS/iSCSI, що виглядає як «повільний диск» на рівні додатка.

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

Завдання 13: Підтвердити, на якому зберіганні ви насправді (LVM/MD/DM)

cr0x@server:~$ lsblk -o NAME,TYPE,SIZE,FSTYPE,MOUNTPOINT
NAME          TYPE  SIZE FSTYPE MOUNTPOINT
nvme0n1       disk  238G
├─nvme0n1p1   part    1G vfat   /boot/efi
└─nvme0n1p2   part  200G ext4   /
nvme1n1       disk  477G
└─nvme1n1p1   part  477G ext4   /data

Значення: RAID/LVM не показано. Якщо хтось казав «воно дзеркалиться», можливо, вони пам’ятають іншу епоху.

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

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

cr0x@server:~$ sudo fio --name=latcheck --filename=/data/fio.test --size=1G --direct=1 --rw=randread --bs=4k --iodepth=32 --runtime=30 --time_based --group_reporting
latcheck: (g=0): rw=randread, bs=(R) 4096B-4096B, (W) 4096B-4096B, (T) 4096B-4096B, ioengine=libaio, iodepth=32
fio-3.28
Run status group 0 (all jobs):
   READ: bw=85.2MiB/s (89.3MB/s), 85.2MiB/s-85.2MiB/s (89.3MB/s-89.3MB/s), io=2556MiB (2681MB), run=30001-30001msec
    slat (nsec): min=800, max=21000, avg=3200.4, stdev=900.1
    clat (usec): min=180, max=12000, avg=340.2, stdev=410.7
     lat (usec): min=190, max=12010, avg=344.0, stdev=411.0
    clat percentiles (usec):
     |  1.00th=[  210],  5.00th=[  230], 10.00th=[  245], 50.00th=[  290],
     | 90.00th=[  520], 95.00th=[  780], 99.00th=[ 2100], 99.90th=[ 7200]

Значення: медіана латентності нормальна, але хвостова латентність жахлива. Спадкові системи часто вмирають від 99.9‑го процентиля.

Рішення: дослідіть періодичні зачіпки (GC, compaction, бекапи, trim, snapshots, гикавки контролера). Оптимізуйте під хвости, а не лише під середні.

Завдання 15: Перевірити здатність бекапів без довіри до розповіді

cr0x@server:~$ sudo -n test -r /var/backups/myapp/latest.sql.gz && echo "backup readable" || echo "backup missing"
backup readable

Значення: наявність і можливість читання — мінімум. Багато тверджень «у нас є бекапи» закінчуються саме тут.

Рішення: заплануйте тест відновлення на scratch‑хості. Якщо не можете відновити — у вас не бекапи, а стиснені жалюзі.

Завдання 16: Перевірити сигнали тихої корупції даних (приклад ZFS)

cr0x@server:~$ sudo zpool status -v
  pool: tank
 state: DEGRADED
status: One or more devices has experienced an error resulting in data corruption.
action: Restore the file in question if possible.  Otherwise restore the entire pool from backup.
  scan: scrub repaired 0B in 00:12:44 with 2 errors on Sun Jan 12 09:40:11 2026
config:

        NAME        STATE     READ WRITE CKSUM
        tank        DEGRADED     0     0     0
          mirror-0  DEGRADED     0     0     0
            sda     ONLINE       0     0     2
            sdb     ONLINE       0     0     0

errors: Permanent errors have been detected in the following files:
        /data/myapp/index/segment-00017

Значення: контрольні суми виявили корупцію. Це не ZFS драматизує; це ZFS робить свою роботу і говорить вам неприємну правду.

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

Три міні‑історії з корпоративного життя

1) Інцидент через неправильне припущення: «Воно ж надлишкове, правда?»

Середня компанія запускала білінговий pipeline на одній Linux‑машині. Усі вірили, що база даних на «дзеркальному RAID»,
бо історично так було. Початковий творець пішов, а поточна команда бачила два диски в шасі і припустила безпеку.
Ніхто не перевіряв роками, бо перевірка здавалася спокусою долі.

Їх перенесли хост у новий стійка під час прибирання дата‑центру. Після ребута система піднялася, попрацювала день, а потім
почала кидати помилки файлової системи під записом. Логи ядра показали I/O таймаути. On‑call зробив розумну річ:
«переключитися» на другий диск. Фейловера не було. Був лише другий диск, відформатований під щось інше, тихо невикористовуваний.

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

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

2) Оптимізація, що обернулась проти: «Ми ввімкнули швидший варіант»

Інша організація мала спадковий Java‑сервіс, який записував дрібні записи на диск і покладався на fsync задля durableності. Він працював
на локальних SSD і поводився передбачувано. Ініціатива продуктивності перемістила його на спільне мережеве сховище, яке пропонувало кращу
утилизацію і централізовані snapshots. Міграція влучила в KPI: середня пропускна спроможність покращилася і команда платформи оголосила перемогу.

Через два тижні система почала відчувати періодичні латентні сплески. Не постійна повільність — сплески. Кожні кілька годин записи зависали,
черги запитів зростали, upstream сервіси тайм‑аутували. Інженери ганялися за GC, пулом потоків і випадковими конфігами.
Хтось «оптимізував» далі, збільшивши concurrency, щоб «сховати латентність». Це підвищило розмір хвиль запису, що погіршило tail latency
платформи зберігання і спричинило ще більші черги. Чистий контур зворотного зв’язку — але невірна пара.

Корінь проблеми — невідповідність: модель durability додатку припускала дешевий fsync; платформа зберігання реалізувала durableність іншим чином
з періодичною фоновою роботою. Додаток не був неправий. Платформа не була неправою. Невірною була пара.

Вони стабілізували ситуацію, обмеживши concurrency, повернувши гарячі журнали на локальний NVMe і лишивши масові дані на спільному бекенді.
Потім вони почали вимірювати p99.9 як перший клас метрики, а не як нотатку в постмортемі. Урок про «оптимізацію» запам’ятався:
якщо ви не вимірюєте tails, ви вимірюєте свій оптимізм.

3) Нудна, але правильна практика, що врятувала ситуацію: «Runbook зробив своє»

Команда фінансових сервісів мала старий batch‑процесор, старший за частину інженерів. Його ніколи не переписували, бо він працював.
Але команда ставилася до нього як до першокласного продакшн‑сервісу: у нього були дашборди, щотижневий тест відновлення і runbook,
що описував режими відмов простими перевірками і відомими добрими базовими значеннями.

Одного вечора час обробки подвоївся. Без помилок. Просто повільніше. On‑call виконав runbook: перевірити завантаження диска, iowait,
NTP, concurrency jobів, нещодавні таймер‑події. За десять хвилин вони знайшли винуватця: logrotate стискав дуже великий лог
на тому ж тому, що і вхідний набір даних, спричиняючи періодичну I/O конкуренцію. Система не була зламана; вона конкурувала.

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

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

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

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

1) «Повільно після міграції» → приховані припущення про fsync → перемістити журнали або змінити стратегію durableності

Симптоми: p99 write latency spikes, заблоковані потоки, таймаути додатка, особливо під час сплесків.

Корінь: навантаження перенесли з локального SSD на мережеве сховище/NFS/iSCSI з іншими семантиками flush і хвостовою латентністю.

Виправлення: тримайте latency‑чутливі WAL/journals на локальному NVMe; бенчмаркуйте за допомогою fio; вимірюйте p99.9; обмежте concurrency і додайте backpressure.

2) «Випадкові краші» → диск заповнений або inode вичерпані → впровадити політики збереження й алерти

Симптоми: сервіси виходять з дивними помилками, lock‑файли не створюються, логи зупиняються, оновлення пакетів падають.

Корінь: файлова система на 95–100% або виснаження inode; спадкові додатки створюють багато дрібних файлів.

Виправлення: налаштувати алерти df -hT і df -i; налаштувати реально працюючий logrotate; перемістити spools з root; встановити квоти, де можливо.

3) «CPU високий, отже це обчислення» → CPU високий через i/o wait або компресію → відокремити сигнал від шуму

Симптоми: високий load average, скарги користувачів, але додавання CPU не допомагає.

Корінь: заблоковані потоки роздувають load; CPU витрачається в ядрі або на компресію; iowait ховається під load.

Виправлення: використовуйте vmstat і iostat -xz; перевіряйте заблоковані задачі в dmesg; виносьте компресію з пікових вікон.

4) «Перезавантажили і стало гірше» → порядок залежностей + stateful recovery → зупиніть рестарт‑шторм

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

Корінь: systemd restart loops плюс довгі warm‑up задачі (реіндексація, rebuild кешу) і насичене сховище.

Виправлення: тимчасово зупиніть сервіс; підтвердіть запас диска; підвищте backoff рестартів; додайте явні залежності і readiness‑перевірки.

5) «Бекапи зелені» → неправильний шлях або порожній набір даних → тестувати відновлення

Симптоми: бекапи «успішні», але відновлення не працює або відновлює порожні дані.

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

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

6) «Сховище каже здорове» → хвостова латентність і мікрозависання → спостерігайте перцентилі і глибину черги

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

Корінь: перевірки платформи фокусуються на середніх; фонові задачі (scrub, trim, snapshot) створюють хвостові сплески.

Виправлення: інструментуйте p95/p99/p99.9 латентності; моніторте device await, глибину черги; перенесіть фонові задачі в інші вікна.

7) «Ми налаштували ядро за блогпостом» → стара порада для нових ядер → повернути baseline і тестувати по одній зміні

Симптоми: непередбачувана латентність, проблеми reclaim пам’яті, дивні зависання після «sysctl tuning».

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

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

8) «Ламається лише на одному вузлі» → розбіг апаратного/прошивкового рівня → забезпечити однорідність і збирати версії

Симптоми: один хост показує більше помилок, іншу латентність або дивні перезавантаження.

Корінь: різні прошивки NVMe, стан кешу RAID контролера, драйвер NIC, налаштування BIOS.

Виправлення: інвентаризувати прошивки і kernel modules; стандартизувати; ізолювати вузол; замінити підозрілі компоненти.

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

Чекліст A: «Торкатися магії» без її ламання

  1. Визначте межу безпеки: які дані ніколи не повинні бути втрачені, який простий час прийнятний, що означає rollback в хвилинах.
  2. Захопіть базу: CPU, пам’ять, диск‑латентність за перцентилями, рівні помилок, глибина черг. Збережіть скріншоти, якщо треба; просто збережіть щось.
  3. Інвентаризація реальності: диски, маунти, RAID/LVM/ZFS, мережеві шляхи, таймери, cron і бекапи. «Ми думаємо» не рахується.
  4. Напишіть першу сторінку runbook: як відрізнити здорове від нездорового і п’ять команд, що це доводять.
  5. Обирайте спочатку оборотну зміну: логування, метрики, read‑only probes або переміщення некритичних записів.
  6. Зробіть одну зміну: одну. Не три «поки ми тут».
  7. Зміряйте знову: якщо не бачите поліпшення чи погіршення — ви не контролювали експеримент.
  8. Документуйте намір: чому зміна зроблена, яку метрику вона впливає і як відкотитися.

Чекліст B: Кроки безпеки, пов’язані зі сховищем (бо на зберіганні кар’єри вмирають)

  1. Перевірте вільне місце та inode на всіх релевантних маунтах; забезпечте цільові запаси.
  2. Підтвердіть твердження про надлишковість командами, а не фольклором.
  3. Підтвердьте очікування durableності записів (частота fsync, режим журналювання, налаштування WAL БД).
  4. Перевірте логи ядра на таймаути пристроїв, ресети і remount‑и файлових систем.
  5. Протестуйте хвостову латентність контрольованим бенчмарком у непіковий час, а не під час інциденту.
  6. Запустіть тест відновлення перед будь‑якою ризиковою міграцією.

Чекліст C: Реагування на інцидент у спадкових системах

  1. Стабілізувати: зупиніть цикл рестартів, обмежте batch‑job‑и, зменшіть трафік за потреби.
  2. Ідентифікувати шар‑вузьке місце: CPU vs пам’ять vs сховище vs мережа.
  3. Підтвердити симптом двома джерелами: ядро + логи додатків або iostat + метрики латентності.
  4. Застосувати найменше пом’якшення: перемістити один гарячий шлях, перенести один таймер, додати один ГБ запасу — не редизайн.
  5. Занотувати, що спрацювало: команди, виводи і часові позначки. Ви пишете завтрашній runbook під тиском.
  6. Після інциденту: перетворіть одне припущення на перевірку, і одну перевірку на алерт.

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

1) Чи правильно іноді казати «не чіпайте»?

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

2) Як почати документувати систему, яку я не розумію?

Почніть з поведінки: входи, виходи, SLO, режими відмов. Потім залежності: маунти сховища, бази даних, мережеві endpoints, cron/timers
і бекап/відновлення. Діаграми архітектури гарні; операційна правда краща.

3) Яка перша метрика, яку додати до спадкового сервісу?

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

4) Чому спадкові системи не люблять спільне сховище?

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

5) Чи варто переписувати?

Не як перша реакція. Спочатку зробіть систему спостережуваною і безпечною в експлуатації. Перепис виправданий, коли вартість зниження ризику
перевищує вартість заміни, або коли залежності (ОС, runtime, постачальник) справді неприпустимі.

6) Як переконати менеджмент, що «стабільне» — це ризик?

Принесіть конкретні тригери: дати EOL ОС, закінчення сертифікатів, єдині точки відмови, відсутність тестів відновлення і виміряну хвостову латентність.
Ризик, що можна заграфати, отримує фінансування швидше, ніж страх.

7) Яка безпечна перша «торкання»?

Додати read‑only спостережуваність: дашборди, логи з correlation IDs, алерти на диск/іноди і практику відновлення бекапу.
Це змінює вашу видимість, а не поведінку продакшну.

8) Як поводитися з «чарівником», що охороняє систему?

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

9) Що якщо система занадто крихка для тестування?

Тоді ваш перший проєкт — створити staging‑середовище або shadow read‑only репліку. Якщо дійсно не можна, зменшуйте ризик, звужуючи
зміни до оборотних конфіг‑перемінних і операційних контролів.

10) Як уникнути карго‑культного налаштування?

Пишіть гіпотезу для кожної зміни: «Це зменшить burstiness checkpoint і знизить p99 latency запису». Вимірюйте до/після. Тримайте план відкату.
Якщо не можете пояснити можливий режим відмови, який ви можете ввести — не шипайте.

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

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

Зробіть це далі, в такому порядку:

  1. Базова лінія та спостережуваність: збережіть знімки iostat/vmstat під нормальним навантаженням; додайте перцентилі латентності до дашбордів.
  2. Інвентаризація сховища: маунти, надлишковість, вільне місце/іноди, логи ядра. Запишіть це.
  3. Доведіть бекапи відновленням: один сухий прогін на scratch‑хості. Заплануйте його.
  4. Зменшіть радіус ураження: відокремте логи/спули від root, додайте ліміти швидкості для batch‑jobів, впровадьте канарки для змін.
  5. Перетворіть припущення на перевірки: якщо хтось каже «воно дзеркалено», автоматизуйте перевірку; якщо кажуть «бекапи в порядку», тестуйте відновлення щомісяця.

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

← Попередня
Знімок Proxmox завис: безпечне очищення залишків LVM-thin
Наступна →
Реплікація Proxmox не вдалася: чому це відбувається і як відновити

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