Запуск триває вічно: єдиний список, який потрібно почистити

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

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

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

Один список: що це насправді

Коли люди кажуть «запуск триває вічно», зазвичай мають на увазі одне з наступного:

  • Час завантаження: kernel + initramfs + init-система, що доводить систему до multi-user (або еквіваленту).
  • Час готовності сервісу: ваш додаток «запустився», але ще не приймає трафік.
  • Час готовності вузла: у Kubernetes/автошкалуванні машина існує, але не може приймати завдання або не проходить health‑checks.

На більшості сучасних Linux список, який потрібно почистити, видно й можна редагувати через systemd. Конкретно це:

  • Набір увімкнених unit-ів, які буде підключено цільовим таргетом (зазвичай multi-user.target або graphical.target).
  • Граф залежностей між ними (Wants/Requires/After/Before, плюс неявні залежності та вихід генераторів).
  • Часові обмеження й порядок на рівні unit-ів, які перетворюють «паралельний старт» на «послідовне очікування».

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

Цитата, яку варто тримати на стікері:

«Надія — це не стратегія.» — перефразована думка, часто приписувана лідерам надійності та операцій

Та сама енергія для продуктивності старту: сподіватися, що система стартуватиме швидше наступного разу, — це не план. Вимірюйте й обрізайте.

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

Ось порядок, який я використовую, коли інстанс повільно піднімається, а люди вже друкують у інцидентному каналі.

Перше: визначте ділянку часу (firmware/kernel проти initramfs проти userspace)

  • Якщо консоль зупиняється перед «Starting version … systemd», підозрюйте firmware, ініціалізацію ядра, initramfs, виявлення сховища або fsck.
  • Якщо systemd стартує швидко, але з’являється «A start job is running…» на 90 секунд — підозрюйте монтування, network‑online чекання або таймаути.
  • Якщо завантаження завершується, але ваш додаток не готовий — підозрюйте readiness‑чеки, міграції, DNS, залежні сервіси або ліміти швидкості.

Друге: знайдіть критичний ланцюг

  • Запустіть systemd-analyze critical-chain і знайдіть, що на шляху до default.target.
  • Перевірте з systemd-analyze blame, але не дайте «blame» вас обдурити: щось може бути повільним, не будучи на критичному шляху.

Третє: підтвердіть, чи затримка — це очікування чи робота

  • Очікування: таймаути, повторні спроби, перевірки залежностей, network‑online, помилки монтування.
  • Робота: CPU‑завантаження при старті unit‑у, дискові fsck, голод за ентропією, блокування менеджера пакетів, завантаження образів контейнерів.

Четверте: ріжте граф, а не кути

  • Видаляйте непотрібні unit-и з таргета завантаження.
  • Послаблюйте порядок (After=), якщо він ґрунтується на забобонах, а не на вимогах.
  • Перетворюйте «жорсткі» залежності на «м’які», коли безпечно (Requires → Wants).
  • Виправляйте або маскуйте речі, що регулярно падають.

Ось такий план. Тепер зробимо його конкретним за допомогою команд і рішень.

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

Аргументи про швидкість завантаження зазвичай релігійні. Не сперечайтеся — вимірюйте. systemd дає чисті структуровані дані, а журнал дає негарну правду.

Дві швидкі дефініції, що важливі на практиці:

  • Час userspace — тут живе більшість ваших налаштувань: сервіси, монтування та логіка залежностей.
  • Критичний шлях — ланцюг unit-ів, затримки яких безпосередньо відтягують досягнення таргета завантаження.

Також: «старт» — це не тільки systemd. Якщо у вас є cloud-init, ignition, агенти управління конфігами, завантаження образів контейнерів або додаток, який виконує міграції при старті — все це може перебити роботу init-системи. Суть залишається: перелічіть те, що робиться при старті, і видаліть те, що не потрібно.

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

Жарт №1: Час завантаження — як зустріч з назвою «швидка синхронізація». Ви не пришвидшите її вірою.

Практичні завдання (команди, виводи, рішення)

Це не «поради». Це завдання. Запустіть їх, прочитайте вивід і прийміть рішення. Це робота.

Завдання 1: Отримайте загальний розподіл часу завантаження

cr0x@server:~$ systemd-analyze
Startup finished in 3.201s (kernel) + 7.842s (initrd) + 1min 18.331s (userspace) = 1min 29.374s
graphical.target reached after 1min 17.902s in userspace

Що це означає: Userspace — проблема: 78 секунд після initrd. Kernel/initrd не є пріоритетом.

Рішення: Залишайтеся в області systemd: критичний ланцюг, blame, упавші unit-и, монти, очікування мережі.

Завдання 2: Знайдіть, що на критичному шляху

cr0x@server:~$ systemd-analyze critical-chain
graphical.target @1min 17.902s
└─multi-user.target @1min 17.902s
  └─docker.service @52.104s +25.769s
    └─network-online.target @51.990s
      └─systemd-networkd-wait-online.service @21.411s +30.563s
        └─systemd-networkd.service @20.982s +428ms
          └─systemd-udevd.service @12.441s +8.512s
            └─systemd-tmpfiles-setup-dev.service @11.901s +526ms

Що це означає: Ланцюг блокується на systemd-networkd-wait-online. Далі в шляху також Docker.

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

Завдання 3: Подивіться список «blame», але не поклоняйтеся йому

cr0x@server:~$ systemd-analyze blame | head -n 15
30.563s systemd-networkd-wait-online.service
25.769s docker.service
10.112s dev-sdb2.device
8.512s systemd-udevd.service
6.902s snapd.service
5.441s cloud-init.service
4.990s apt-daily.service
4.221s systemd-journald.service
3.301s systemd-tmpfiles-setup.service
2.880s systemd-logind.service

Що це означає: У вас є кілька повільних unit-ів, але тільки ті, що на критичному шляху, відтягують досягнення таргета завантаження.

Рішення: Виправте wait-online спочатку (критичний шлях), потім перегляньте Docker і все інше, що вас цікавить.

Завдання 4: Перелік упавших unit-ів (часто прихований податок завантаження)

cr0x@server:~$ systemctl --failed
  UNIT                         LOAD   ACTIVE SUB    DESCRIPTION
● mnt-backup.mount             loaded failed failed /mnt/backup
● nfs-client.target            loaded failed failed NFS client services

LOAD   = Reflects whether the unit definition was properly loaded.
ACTIVE = The high-level unit activation state, i.e. generalization of SUB.
SUB    = The low-level unit activation state, values depend on unit type.

Що це означає: Монтування й NFS‑клієнт не вдались. У деяких конфігураціях systemd чекатиме або робитиме повторні спроби, що коштує часу.

Рішення: Виправте монтування, або зробіть його неблокуючим (таймаути, nofail, automount), або видаліть його зі старту.

Завдання 5: Перевірте довгі очікування в журналі для цього завантаження

cr0x@server:~$ journalctl -b -0 -p warning..alert --no-pager | tail -n 30
Jan 12 10:04:21 server systemd[1]: mnt-backup.mount: Mount process exited, code=exited, status=32/n/a
Jan 12 10:04:21 server systemd[1]: Failed to mount /mnt/backup.
Jan 12 10:04:21 server systemd[1]: Dependency failed for Local File Systems.
Jan 12 10:04:52 server systemd-networkd-wait-online[418]: Timeout occurred while waiting for network connectivity.
Jan 12 10:04:52 server systemd[1]: systemd-networkd-wait-online.service: Failed with result 'timeout'.

Що це означає: Дві класичні причини повільного старту: помилка монтування і таймаут wait-online.

Рішення: Виправте семантику монтування і видаліть вимогу wait-online, якщо вузол справді не залежить від неї.

Завдання 6: Визначте, які unit-и вимагають network-online.target

cr0x@server:~$ systemctl list-dependencies --reverse network-online.target
network-online.target
● └─docker.service
● └─remote-fs.target
● └─myapp.service

Що це означає: Docker, віддалені файлові системи і ваш додаток тягнуть за собою network-online. Через це wait блокує все.

Рішення: Для кожного з них вирішіть, чи потрібен network.target (базова мережа) замість network-online.target (сконфігурована, «up»). Більшість демонов можуть терпіти, що мережа з’явиться трохи пізніше.

Завдання 7: Підтвердіть, хто тягне за собою повільне монтування і чи можна зробити його на вимогу

cr0x@server:~$ systemctl list-dependencies mnt-backup.mount
mnt-backup.mount
● ├─system.slice
● └─remote-fs-pre.target

Що це означає: Це монтування обробляється як частина налаштування файлових систем. Якщо воно блокує, то блокує рано.

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

Завдання 8: Аудит /etc/fstab на предмет небезпечних для старту записів

cr0x@server:~$ cat /etc/fstab
UUID=9bb0c7d9-4f4d-4d56-9b27-2cbd71a7dbd6 / ext4 defaults 0 1
server:/exports/backup /mnt/backup nfs defaults 0 0

Що це означає: Це NFS‑монтування не має nofail, не має x-systemd.automount і не має опцій таймауту. Воно охоче затримає завантаження, поки пробує підключитися.

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

cr0x@server:~$ sudo sed -i 's#server:/exports/backup /mnt/backup nfs defaults 0 0#server:/exports/backup /mnt/backup nfs nofail,x-systemd.automount,x-systemd.idle-timeout=60,timeo=5,retrans=2 0 0#' /etc/fstab

Додаткове рішення: Після редагування перевірте за допомогою systemctl daemon-reload і протестуйте монтування (наступне завдання). Не відправляйте необтестовані зміни /etc/fstab; саме так настає «ніч без завантаження» для віддалених систем.

Завдання 9: Перевірте поведінку монтування без перезавантаження

cr0x@server:~$ sudo systemctl daemon-reload
cr0x@server:~$ sudo systemctl restart mnt-backup.automount
cr0x@server:~$ ls -la /mnt/backup
total 8
drwxr-xr-x  2 root root 4096 Jan 12 10:06 .
drwxr-xr-x  4 root root 4096 Jan 12 10:06 ..

Що це означає: З automount монтування відбувається при доступі. Якщо сервер недоступний, ви отримаєте затримку під час доступу, а не під час старту.

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

Завдання 10: Приберіть «wait-online», якщо це забобон

cr0x@server:~$ systemctl is-enabled systemd-networkd-wait-online.service
enabled
cr0x@server:~$ sudo systemctl disable systemd-networkd-wait-online.service
Removed "/etc/systemd/system/network-online.target.wants/systemd-networkd-wait-online.service".

Що це означає: Вимкнення wait-online означає, що network-online.target все ще може бути досягнутий іншим шляхом, але явний крок «чекати, поки онлайн» видалено.

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

Завдання 11: Знайдіть, які сервіси ввімкнені і, ймовірно, не повинні бути

cr0x@server:~$ systemctl list-unit-files --state=enabled --no-pager | head -n 25
UNIT FILE                              STATE   PRESET
apt-daily.service                       enabled enabled
apt-daily.timer                         enabled enabled
cloud-init.service                      enabled enabled
cloud-init-local.service                enabled enabled
cloud-config.service                    enabled enabled
cloud-final.service                     enabled enabled
docker.service                          enabled enabled
snapd.service                           enabled enabled
ssh.service                             enabled enabled
systemd-timesyncd.service               enabled enabled

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

Рішення: Для серверів (не десктопів) поставте під сумнів фонові оновлювачі (apt-daily), snap якщо він вам не потрібен, і все, що пов’язане з cloud-init на образах, які вже не є першими завантаженнями.

Завдання 12: Перевірте, на що чекає сервіс (читайте unit‑файл як контракт)

cr0x@server:~$ systemctl cat myapp.service
# /etc/systemd/system/myapp.service
[Unit]
Description=My App API
After=network-online.target remote-fs.target
Wants=network-online.target

[Service]
Type=simple
ExecStart=/usr/local/bin/myapp --config /etc/myapp/config.yml
Restart=on-failure
TimeoutStartSec=120

[Install]
WantedBy=multi-user.target

Що це означає: Ваш додаток явно тягне за собою network-online і remote-fs. Якщо будь‑яке з них нестабільне, ваш додаток стає якірним елементом завантаження.

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

  • After=network.target (або взагалі видаліть порядок)
  • Приберіть remote-fs.target, якщо ви насправді не потребуєте віддалених монтувань
  • Тримайте TimeoutStartSec коротким і осмисленим

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

cr0x@server:~$ systemd-analyze verify /etc/systemd/system/myapp.service
/etc/systemd/system/myapp.service:8: Unknown lvalue 'TimeoutStartSec' in section 'Service'

Що це означає: Верифікація ловить помилки конфігурації, через які systemd може ігнорувати налаштування, які ви вважали активними. У цьому прикладі варто з’ясувати, чому (старий systemd? опечатка? перекриті секції?).

Рішення: Розглядайте попередження парсингу unit-ів як production‑помилки. Виправляйте їх. Неправильно прочитані конфіги створюють петлі «чому все ще повільно?».

Завдання 14: Знайдіть реальний час, витрачений у mount unit-ах

cr0x@server:~$ systemd-analyze blame | grep -E '\.mount$|remote-fs' | head -n 20
1min 30.002s mnt-backup.mount
12.443s remote-fs.target

Що це означає: Одне це монтування коштує 90 секунд. Це не «дрібна оптимізація». Це ситуація «прибрати з завантаження».

Рішення: Перенесіть у automount, скоротіть таймаут, додайте nofail або видаліть зовсім. Якщо воно потрібне для коректності, інвестуйте в надійність віддаленого сервісу та швидкість.

Завдання 15: Перевірте, чи DNS не є прихованим очікуванням мережі

cr0x@server:~$ resolvectl status
Global
       Protocols: -LLMNR -mDNS -DNSOverTLS DNSSEC=no/unsupported
resolv.conf mode: stub

Link 2 (ens5)
    Current Scopes: DNS
         Protocols: +DefaultRoute
Current DNS Server: 10.0.0.2
       DNS Servers: 10.0.0.2 10.0.0.3

Що це означає: DNS виглядає налаштованим, але це не доводить, що він досяжний під час старту. Багато очікувань network-online насправді маскують «DNS ще не готовий».

Рішення: Якщо ви використовуєте локальний резольвер або залежність, яка не готова рано — відділіть завантаження від DNS, уникайте монтувань по іменах хостів і забезпечте наявність резольверів (або використовуйте IP‑адреси там, де доречно).

Завдання 16: Проінспектуйте затримки в initramfs (сховище та драйвери)

cr0x@server:~$ dmesg --color=never | grep -E 'EXT4-fs|fsck|timed out|nvme|scsi|link is not ready' | tail -n 25
[    2.901234] nvme nvme0: I/O 14 QID 0 timeout, reset controller
[    3.112345] nvme nvme0: reset controller
[    8.554321] EXT4-fs (nvme0n1p2): recovery complete

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

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

Завдання 17: Перевірте здоров’я диска і очікувані помилки (нудно, але ефективно)

cr0x@server:~$ sudo smartctl -a /dev/sda | egrep -i 'Reallocated|Pending|Uncorrect|Power_On_Hours|SMART overall'
SMART overall-health self-assessment test result: PASSED
Power_On_Hours: 18234
Reallocated_Sector_Ct: 0
Current_Pending_Sector: 0
Offline_Uncorrectable: 0

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

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

Завдання 18: Виявіть «податок fsck» при старті

cr0x@server:~$ journalctl -b -0 --no-pager | grep -E 'fsck|clean|recovering|UNEXPECTED' | head -n 20
Jan 12 10:03:11 server systemd-fsck[201]: /dev/nvme0n1p2: clean, 245612/6553600 files, 12541021/26214400 blocks

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

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

Завдання 19: Знайдіть генератори, що створюють unit-и при старті

cr0x@server:~$ systemd-analyze unit-paths
/etc/systemd/system.control
/run/systemd/system.control
/run/systemd/transient
/run/systemd/generator.early
/etc/systemd/system
/run/systemd/system
/run/systemd/generator
/usr/local/lib/systemd/system
/usr/lib/systemd/system
/run/systemd/generator.late

Що це означає: Генератори синтезують unit-и з речей типу fstab, crypttab, kernel cmdline і мережевих конфігів. Вони можуть створювати сюрпризи.

Рішення: Якщо у вас постійно з’являються «таємні монтування» або таргети, дивіться /run/systemd/generator* після завантаження, щоб побачити, що створено і чому.

Завдання 20: Підтвердіть, що саме увімкнено для стандартного таргета

cr0x@server:~$ systemctl get-default
graphical.target
cr0x@server:~$ systemctl list-dependencies graphical.target --no-pager | head -n 30
graphical.target
● ├─multi-user.target
● ├─display-manager.service
● └─system.slice

Що це означає: Якщо це сервер, graphical.target викликає підозру. Можливо, ви завантажуєте GUI‑стек, який не потрібен.

Рішення: На серверах поставте multi-user.target, якщо у вас немає реальної потреби в графічному сеансі.

Жарт №2: Включити кожен стартовий сервіс «на всякий випадок» — це як брати бігову доріжку в похід. Технічно можливо; духовно невірно.

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

Симптом: «A start job is running for /mnt/…»

Корінь проблеми: Монтування під час старту, яке не можна задовольнити (NFS/CIFS/iSCSI недоступний, неправильний DNS, VPN ще не піднятий), у поєднанні зі стандартними таймаутами й жорсткими залежностями.

Виправлення: Якщо опціональне: додайте nofail, розгляньте x-systemd.automount, скоротіть таймаути або видаліть зі /etc/fstab. Якщо обов’язкове: зробіть залежність надійною й забезпечте мережевий шлях на ранньому етапі.

Симптом: Завантаження блокується на network-online, але мережа «працює пізніше»

Корінь проблеми: systemd-networkd-wait-online (або еквівалент NetworkManager) чекає на умову, яка ніколи не настає: затримка DHCP, відсутність carrier, відключений інтерфейс або вимога до DNS.

Виправлення: Вимкніть wait-online глобально, якщо безпечно; частіше — приберіть Wants=network-online.target з сервісів, що цього не потребують. Якщо один сервіс потребує — застосуйте scope до нього і зробіть його надійним (повтори/зворотні інтервали).

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

Корінь проблеми: З’явилися нові увімкнені unit-и (телеметрія, автооновлювачі, сканери безпеки), нові таймери або cloud-init перезапускається на кожному старті, бо стан не було збережено правильно.

Виправлення: Аудитуйте увімкнені unit-и, порівняйте з базовою конфігурацією і вимкніть те, що не потрібне. Зробіть cloud-init одноразовим, виправивши поведінку з метаданими/станом інстансу.

Симптом: systemd-analyze blame показує повільний unit, але critical-chain — ні

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

Виправлення: Пріоритет — за критичним шляхом. Оптимізуйте паралельні unit-и тільки якщо вони змагаються за CPU/диск і реально шкодять готовності або SLO.

Симптом: Сервіс додатку стартує швидко, але health‑checks падають хвилинами

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

Виправлення: Зробіть readiness явним. Вийміть важку роботу з гарячого шляху. Додайте backoff, таймаути та правильні перевірки залежностей. Розділіть міграції від запуску веба, якщо вам важлива швидкість старту.

Симптом: Випадкові повільні старти; інколи швидко, інколи жахливо

Корінь проблеми: Зовнішні залежності (DNS, NTP, metadata service, віддалені монтування), голод за ентропією або флаттер інтерфейсів мережі.

Виправлення: Приберіть жорсткий порядок, додайте кешування або локальні fallback‑и, використовуйте таймаути, що падають швидко. Також перевірте апарат і віртуалізаційний шар на предмет проблем.

Симптом: «Раніше було швидко; тепер повільно на тому ж хості»

Корінь проблеми: Накопичення override‑ів unit‑ів, застарілі генераторні припущення або перейменування mount/device (наприклад, зміна label), що викликає затримки при виявленні.

Виправлення: Перегляньте drop-in та override; запустіть systemd-delta, щоб побачити зміни; прив’яжіть монти по UUID; приберіть старі кастомні unit‑и.

Симптом: Завантаження зависає перед запуском systemd

Корінь проблеми: Initramfs чекає root‑пристрій, таймаути сховища, зламаний initramfs або регресії драйверів.

Виправлення: Використовуйте логи консолі/ dmesg, перевірте конфігурацію initramfs, підтвердіть ідентифікатори root‑пристрою і відкотіть kernel/initramfs, якщо потрібно. systemd тут ще не винуватий.

Три міні-історії з реального світу

1) Інцидент через неправильне припущення: «network-online означає «інтернет»»

У середній компанії команда стандартизувала базовий образ і додала просте правило: «Запускайте API після того, як мережа буде онлайн». Звучить розумно, правда? Вони оновили unit з After=network-online.target і Wants=network-online.target. Все пройшло тести в стейджингу, бо там був чистий DHCP і один інтерфейс.

Продакшн був складніший. Інстанси мали два NIC: один для внутрішнього трафіку, інший — для обмеженої мережі управління без дефолтного маршруту за задумом. Під час старту логіка wait-online systemd чекала, що обидва лінки будуть «сконфігурованими». Мережа управління ніколи не виконувала вимоги, які очікував сервіс. Wait-online досягнув таймауту, і ланцюг залежностей утримував API.

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

Виправлення було надзвичайно непривабливим: змінити додаток на старт після network.target, прибрати глобальну вимогу wait-online і додати логіку повторних підключень до upstream. Вони також налаштували wait-online, щоб воно цікавилось лише потрібним інтерфейсом (коли це справді було необхідно). Справжня помилка — припустити, що «онлайн» — це одностайна істиною. У реальних мережах це умовно, і за таку уяву доводиться платити.

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

Велика команда платформи захопилася часом старту, бо в них тисячі нод і вони хотіли швидші rolling updates. Вони пішли за systemd-analyze blame і знайшли кілька довгих сервісів: логування, метрики і агент безпеки. Хтось запропонував «просте покращення»: скоротити TimeoutStartSec по всій системі і видалити ordering, щоб усе стартувало одночасно.

Роллаут виглядав чудово день-два. Завантаження стало швидшим. Дашборди зелені. Потім почалися дивності. Агент безпеки інколи не стартував через повільний диск або конкуренцію за CPU під час старту. systemd позначав його як failed, але нода досягала таргета і ставала готовою приймати трафік. Команда комплаєнсу помітила це першою, і це ніколи не найприємніший моніторинг.

Гірше — інколи pipeline логування стартував ще до стабілізації DNS, не зміг резолвити upstream і виходив. Через те, що його «оптимізували» під швидкий старт, стратегія перезапуску була недостатньою. Ноди піднімались «успішно», але без потрібних логів. Коли через два тижні сталася інша продакшн‑проблема, у половини нод телеметрія була неповною. Розбір причин перетворився на археологію.

Виправлення полягало в тому, щоб поводитися з продуктивністю старту як з trade‑off SLO, а не як зі спринтом. Вони повернули здорові таймаути для критичних сервісів безпеки/телеметрії, додали надійний restart/backoff і відновили порядок там, де він відображав реальні залежності. Вони все ще прискорили старт — прибравши сміття зі списку запуску і виправивши монтування — але припинили обманювати себе, роблячи важливі сервіси випадково опціональними.

3) Нудна, але правильна практика, що врятувала день: «Базуйте список unit-ів і робіть diff»

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

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

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

Нічого героїчного не сталося. Жодної «воєнної кімнати». Жодного фанфіку «SRE врятував день». Просто невеликий процес, який не давав списку запуску невідчутно набути зубів. Ось до чого варто прагнути.

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

  • Раніше час завантаження був переважно обмежений апаратним забезпеченням. На старих системах BIOS/firmware і механічні диски домінували. Нині ж на серверах часто панує userspace‑граф залежностей.
  • SysV init був здебільшого послідовним. Перехід до систем init на основі залежностей (не лише systemd) зробив паралельний старт можливим, але також зробив неправильні залежності дорожчими в наслідках.
  • systemd ввів socket‑activation. Сервіси можуть стартувати за потреби при отриманні з’єднання, що є одним із найчистіших способів тримати їх поза критичним шляхом.
  • fstab старший за більшість вашої інфраструктури. Це простий файл, але в епоху systemd він живить генератори, що можуть створювати складну поведінку unit‑ів.
  • «Онлайн» мережі за задумом неоднозначне поняття. Carrier up, IP сконфігуровано, дефолтний маршрут є, DNS доступний — це різні етапи, і різні інструменти визначають «онлайн» по‑різному.
  • Таймаути за замовчуванням часто консервативні. 90‑секундний таймаут монтування міг мати сенс, коли мережі були повільні й серверів було мало. У масштабі це самостійно створює відмови.
  • cloud-init змінив поведінку першого старту. У хмарних образах велика частина «часу старту» часто — це «час конфігурації інстансу». Якщо він перезапускається випадково — старт роздувається.
  • Журнали файлових систем зменшили довгі події fsck, але не ліквідували їх. Якщо ви бачите часті ремонти — це зазвичай симптом некоректних вимкнень або нестабільності сховища.
  • Паралелізм може збільшувати варіативність. Коли все стартує одночасно, конкуренція призводить до того, що «зазвичай швидко» стає «іноді жахливо». Ось чому важлива логіка критичного шляху.

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

Фаза 1: Встановіть базу (той же день)

  1. Зніміть вивід systemd-analyze.
  2. Зніміть systemd-analyze critical-chain для поточного дефолтного таргета.
  3. Збережіть systemd-analyze blame (топ‑50 рядків зазвичай достатньо).
  4. Збережіть systemctl --failed і попередження/помилки з journalctl -b.

Мета: Знати, у якій ви категорії і який unit блокує старт.

Фаза 2: Почистіть список (1–3 дні, залежно від політики)

  1. Приберіть блокатори старту: виправте/зробіть опціональними віддалені монтування; вимкніть непотрібне wait-online; приберіть GUI‑таргети на серверах.
  2. Зменшіть увімкнені unit-и: вимкніть сервіси, які вам не потрібні на серверах (десктопний багаж, невикористані агенти, таймери оновлень під час старту).
  3. Спроостіть ребра залежностей: приберіть After=, що походить із забобонів; перетворіть Requires на Wants, якщо безпечно; уникайте потягування remote-fs і network-online, якщо це не справді необхідно.
  4. Встановіть адекватні таймаути: скоротіть таймаути монтувань для опціональних ресурсів; встановіть TimeoutStartSec у значення, що відображає реальність і швидко падає для некритичних сервісів.

Мета: Скоротити довжину критичного шляху і зменшити варіативність.

Фаза 3: Закріпіть результат (постійно)

  1. Базуйте список увімкнених unit-ів і робіть diff між версіями образу.
  2. Контролюйте увімкнення нових сервісів: вимагайте обґрунтування в рев’ю змін.
  3. Тестуйте час старту в CI для змін базового образу (навіть базовий smoke‑тест допомагає).
  4. Для додатків впровадьте semantics готовності: started ≠ ready.

Мета: Запобігати регресіям, а не лише виправляти поточний безлад.

Чого уникати (бо це відбирає тижні)

  • Сліпе вимикання «повільних» сервісів без розуміння того, що вони надають.
  • Заниження таймаутів повсюдно, щоб старт «виглядав швидким». Це просто ховає проблему надійності.
  • Гонитва за верхнім рядком у blame, ігноруючи critical-chain.
  • Припущення, що повільна частина — це ваш додаток, коли система чекає на сховище/мережу.

FAQ

1) Що таке «один список», якщо я не використовую systemd?

Це та сама концепція: набір дій при старті плюс їхні обмеження порядку. В OpenRC це runlevel-и і залежності; в класичних init‑скриптах — порядок rc. Логіка очищення не змінюється: обрізайте, декуплюйте і приберіть жорсткі очікування.

2) Чи достатньо systemd-analyze blame?

Ні. Він корисний, але не дає звіт про критичний шлях. Повільний unit, що стартує паралельно, може не відтягувати досягнення таргета. Використовуйте critical-chain, щоб знайти, що саме блокує.

3) Чи варто вимикати systemd-networkd-wait-online?

Часто так, на серверах. Але робіть це свідомо: перевірте, які сервіси реально вимагають network-online.target. Якщо потрібний лише один сервіс — залиште вимогу локально для нього, а не глобально.

4) Який найнадійніший спосіб обробки опціональних NFS/CIFS монтувань?

Використовуйте nofail і x-systemd.automount, щоб завантаження не блокувалось. Контролюйте поведінку при доступі розумними таймаутами. Опціональне — означає опціональне під час старту.

5) Мій додаток потребує бази даних. Хіба це не означає, що він має чекати network-online?

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

6) Чи контейнери можуть уповільнювати старт, навіть якщо systemd швидкий?

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

7) Як запобігти регресіям часу старту з часом?

Базуйте список увімкнених unit-ів і робіть diff при кожному релізі образу. Також зберігайте метрики часу старту і сигналізуйте про регресії так само, як ви сигналізуєте про регреси в затримках сервісів.

8) Що робити, якщо повільна частина до systemd?

Тоді налаштування systemd не допоможе. Використовуйте логи консолі і dmesg, щоб знайти таймаути при виявленні сховища, очікування в initramfs, проблеми з драйверами або fsck. Виправляйте пристрій/драйвер/конфігурацію.

9) Чи змінювати дефолтний таргет з graphical на multi-user — це справжня економія?

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

10) У чому різниця між «зробити щось швидким» і «зробити так, щоб воно не блокувало старт»?

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

Висновок: наступні кроки, що дійсно мають значення

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

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

  1. Запустіть швидкий план діагностики і знайдіть блокатор критичного шляху.
  2. Приберіть блокатори завантаження: опціональні віддалені монтування зробіть automount/nofail; wait-online зробіть scoped або вимкніть.
  3. Обріжте увімкнені unit-и, щоб вони відповідали призначенню сервера. Якщо процес не обслуговує трафік, не зберігає дані і не надає критичну безпеку/телеметрію — він не повинен знаходитися в списку запуску.
  4. Закодуйте базову конфігурацію увімкнених unit-ів і метрик часу старту, і робіть diff при кожній зміні образу. Регресія — це стан за замовчуванням у Всесвіті; вам потрібна документація, щоб боротися з фізикою.

Якщо ви почистите список і будете його підтримувати в чистоті, старт перестане бути трилером. Він стане нудною, відтворюваною процедурою. У продакшні нудність — це перевага.

← Попередня
«Antimalware Service Executable» — високе завантаження CPU: виправити без відключення захисту
Наступна →
Апаратний GPU: кабелі живлення, шини і PCIe та «брехня» про сумісність

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