Піки CPU кожні кілька хвилин: заплановане завдання, яке слід перевірити насамперед

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

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

Якщо піки періодичні, вважайте їх наслідком запланованого завдання, поки не доведено інше. І перше заплановане завдання, яке варто перевірити — це те, яке ви не ставили: системні таймери та сторонні агенти, а не ваш застосунок. Конкретно: systemd timers and cron (плюс їх «дружні» співавтори, як logrotate, updatedb, apt timers, агенти моніторингу та клієнти резервного копіювання).

Швидкий план діагностики (перші 10 хвилин)

Періодичні піки — це подарунок. Випадкові піки — роман жахів. Періодичні піки — як запрошення в календарі.

Хвилина 0–2: підтвердити патерн і зловити винуватця

  1. Підтвердьте періодичність. Подивіться на моніторинг: чи піки відбуваються кожні 1, 5, 10, 15, 60 хвилин, або в :00 чи :30? Це класичні каденси таймерів.
  2. Під час наступного піку зловіть найактивніші процеси. Використайте top або pidstat. Не «подивіться пізніше»; ім’я процесу — половина боротьби.
  3. Перевірте чергу виконання та iowait. Високий %usr/%sys вказує на CPU-опрацювання; високий %wa — на вузьке місце в I/O з побічними ефектами на CPU (сжаття, контрольні суми, робота на зразок fsck, шифрування тощо).

Хвилина 2–6: ідентифікуйте планувальник

  1. Перелічіть systemd timers. Це ловить випадки «я клянуся, тут немає cron».
  2. Перелічіть джерела cron. Користувацькі crontab, /etc/crontab та директорії /etc/cron.*.
  3. Перевірте сторонні агенти та моніторинг. Багато з них встановлюються як systemd-сервіси й самі планують свої запуски.

Хвилина 6–10: зіставте з логами й вжийте безпечної дії

  1. Зіставте по часу. Журнали журналу навколо часу піку зазвичай покажуть юніт, який запустився.
  2. Найбезпечніша негайна міра. Якщо це не критично (updatedb, logrotate, звітний скрипт) — відкладіть або додайте життер. Якщо критично (резервні копії, сканування безпеки) — зменшіть паралелізм або обсяг, а не відключайте.

Парафраз ідеї, приписаної Gene Kim: Надійність походить від того, щоб робота була видимою й повторюваною, а не від героїзму о 3-й ранку.

Чому періодичні піки кричать «заплановане завдання»

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

Періодичні піки CPU зазвичай походять з однієї з цих категорій:

  • Технічні роботи: logrotate, updatedb (mlocate), очищення tmp, перевірки оновлень пакетів, хуки оновлення сертифікатів.
  • Резервні копії та індексація: сканування файлових систем, скрипти знімків, індексація дедупа, синхронізація об’єктного сховища, антивірусні сканування.
  • Моніторинг та телеметрія: збирання метрик, колектори інвентарю, перевірки безпеки.
  • CPU-робота збереження: стиснення, контрольні суми, шифрування, RAID-парність, операції scrub, обчислення різниць снапшотів.
  • «Корисність» застосунку: прогрів кешів, періодична генерація звітів, компактація (БД), роботи з перевіндексування.

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

Жарт №1: Заплановані завдання як офісні дні народження — якось вони трапляються щороку й якось досі дивують усіх.

Яке заплановане завдання перевірити насамперед (і чому)

Перше, що я перевіряю — це systemd timers, потім cron. Не тому, що cron рідкісний — cron скрізь — але команди часто перевіряють «cron» і зупиняються. Тим часом systemd timers тихо спрацьовують:

  • apt-daily.timer і apt-daily-upgrade.timer (Debian/Ubuntu)
  • fstrim.timer (SSD trim; може навантажувати підсистеми збереження)
  • logrotate.timer (або logrotate через cron, залежно від дистрибутива)
  • man-db.timer (так, справді)
  • updatedb.timer (сканування файлової системи)
  • Таймери вендорних агентів для бекапу, EDR, сканерів відповідності

Чому перше? Тому що systemd timers можуть мати поведінку напівпідхоплення (persistent catch-up). Якщо хост був вимкнений у запланований час, таймер з Persistent=true може спрацювати одразу при завантаженні. Ось як після збою ви отримуєте «піки CPU кожні кілька хвилин»: зграя пропущених таймерів, що надолужують згаяне.

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

Практично: 12+ кроків з командами, виводами та рішеннями

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

Завдання 1: Слідкуйте за CPU по процесах у часі (зловіть пік)

cr0x@server:~$ pidstat -u -h 1
Linux 6.5.0 (server)  02/05/2026  _x86_64_  (16 CPU)

# Time        UID      PID    %usr %system  %CPU   Command
12:00:01     0       1423     0.00    0.00  0.00   systemd
12:00:02     0      22891    92.00    6.00  98.00  updatedb
12:00:03     0      22891    88.00    5.00  93.00  updatedb

Значення: updatedb насичує CPU під час піку. Це не ваш застосунок. Це заплановане індексування файлової системи.

Рішення: Визначте, хто запускає updatedb (таймер чи cron), потім перенастройте розклад, обмежте або виключіть шляхи.

Завдання 2: Підтвердіть режим CPU (user/system/iowait)

cr0x@server:~$ mpstat -P ALL 1 5
Linux 6.5.0 (server)  02/05/2026  _x86_64_  (16 CPU)

12:00:01 PM  all  %usr %nice %sys %iowait %irq %soft %steal %idle
12:00:01 PM  all  62.50  0.00 12.30  0.20 0.00  0.50   0.00 24.50
12:00:02 PM  all  89.10  0.00  8.40  0.10 0.00  0.40   0.00  2.00

Значення: Високий %usr вказує на чисті обчислення (хешування/сжаття/сканування), а не на очікування диска.

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

Завдання 3: Побачити середнє навантаження проти черги виконання (CPU contention vs «просто зайнято»)

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
 1  0      0  81234  10240 913024    0    0     2     5  120  300 12  3 85  0  0
12  0      0  80120  10240 913500    0    0     0     0 3400 9800 88  9  3  0  0

Значення: r=12 на 16‑ядерній машині означає багато виконуваних потоків; вони не заблоковані, а просто конкурують за CPU.

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

Завдання 4: Перелічіть systemd timers (звичні підозрювані)

cr0x@server:~$ systemctl list-timers --all
NEXT                         LEFT          LAST                         PASSED       UNIT                         ACTIVATES
Mon 2026-02-05 12:05:00 UTC  2min 12s      Mon 2026-02-05 12:00:01 UTC  2min 47s     updatedb.timer               updatedb.service
Mon 2026-02-05 12:10:00 UTC  7min 12s      Mon 2026-02-05 12:00:08 UTC  2min 40s     apt-daily.timer              apt-daily.service
Mon 2026-02-05 12:15:00 UTC  12min 12s     Mon 2026-02-05 12:00:10 UTC  2min 38s     logrotate.timer              logrotate.service

Значення: У вас кілька таймерів, що спрацьовують на нульовій хвилині й повторюються. Поле LAST — золото: співставте його з часом піку CPU.

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

Завдання 5: Перевірте визначення таймера та сервісу (що саме виконується)

cr0x@server:~$ systemctl cat updatedb.timer
# /lib/systemd/system/updatedb.timer
[Unit]
Description=Update a database for mlocate

[Timer]
OnCalendar=*:0/5
Persistent=true
RandomizedDelaySec=0

[Install]
WantedBy=timers.target

Значення: Кожні 5 хвилин, persistent catch-up і нульовий життер. Це практично запрошення до синхронізованого болю.

Рішення: Додайте RandomizedDelaySec, зменшіть частоту або відключіть, якщо вам не потрібен locate на сервері.

Завдання 6: Перевірте cron (системний і для користувачів)

cr0x@server:~$ sudo ls -l /etc/cron.hourly /etc/cron.daily /etc/cron.d
/etc/cron.d:
total 12
-rw-r--r-- 1 root root  240 Jan 10  2026 backup-agent
-rw-r--r-- 1 root root  180 Dec  2  2025 mlocate
-rw-r--r-- 1 root root  210 Nov 18  2025 sysstat

Значення: Cron ще грає роль. /etc/cron.d/mlocate ймовірно запускає updatedb на дистрибутивах, які не використовують таймер, або додатково до нього.

Рішення: Переконайтесь, що немає дублювання розкладу (таймер + cron). Виберіть один і відключіть інший.

Завдання 7: Перегляньте crontab для конкретного користувача (там ховаються сюрпризи)

cr0x@server:~$ sudo crontab -l -u root
*/5 * * * * /usr/local/sbin/inventory-scan --json --upload
15 * * * * /usr/local/sbin/storage-report

Значення: П’ятихвилинний каденс видно одразу. inventory-scan нагадує «агентську роботу», часто важку для CPU (ходіння по файловій системі, опитування пакетів, хешування).

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

Завдання 8: Зіставте з журналом systemd у часі піку

cr0x@server:~$ sudo journalctl --since "2026-02-05 11:58:00" --until "2026-02-05 12:02:00" --no-pager
Feb 05 12:00:01 server systemd[1]: Started Update a database for mlocate.
Feb 05 12:00:01 server updatedb[22891]: updatedb: pruning "/var/lib/docker/overlay2"
Feb 05 12:00:10 server systemd[1]: Started Rotate log files.
Feb 05 12:00:10 server logrotate[22940]: rotating pattern: /var/log/*.log  forced from command line (1 rotations)

Значення: Тепер у вас є хронологія. Це не «таємне навантаження»; це два технічні завдання, що нашаровуються.

Рішення: Рознесіть їх у часі. Нашарування технічних робіт — класична причина «чому піки гірші опівночі?».

Завдання 9: Визначте, до якої cgroup/юніта належить гарячий PID

cr0x@server:~$ cat /proc/22891/cgroup
0::/system.slice/updatedb.service

Значення: Процес належить updatedb.service. Це полегшує налаштування за допомогою systemd-опцій.

Рішення: Застосуйте CPUQuota, Nice або IOSchedulingClass у drop-in, якщо не можете змінити саме завдання.

Завдання 10: Подивіться, з якою командою процес справді запущений

cr0x@server:~$ ps -p 22891 -o pid,ppid,ni,etimes,cmd
  PID  PPID  NI ELAPSED CMD
22891     1   0      18 /usr/bin/updatedb.mlocate --prunepaths=/tmp /var/lib/docker /var/lib/kubelet

Значення: Він сканує важкі директорії (Docker, kubelet). Ці шляхи активно змінюються й містять мільйони інодів. Це CPU плюс metadata I/O.

Рішення: Виключіть ці шляхи або припиніть запуск updatedb на хостах з контейнерами. «Locate» — не SLO продакшена.

Завдання 11: Перевірте історію піків CPU через sar (доведіть періодичність)

cr0x@server:~$ sar -u -s 11:30:00 -e 12:10:00
Linux 6.5.0 (server)  02/05/2026  _x86_64_  (16 CPU)

11:35:00 AM     %user     %system     %iowait      %idle
11:35:00 AM      6.20        1.10        0.10      92.60
11:40:00 AM     68.30        8.90        0.20      22.60
11:45:00 AM      7.10        1.20        0.10      91.60
11:50:00 AM     70.40        9.10        0.10      20.40
11:55:00 AM      6.90        1.00        0.10      92.00
12:00:00 PM     71.20        9.00        0.10      19.70

Значення: Піки кожні 10 хвилин (або кожні 5 хвилин залежно від вибірки). Це збігається з таймерами і cron.

Рішення: Припиніть сперечатися «це наш застосунок чи ні?» і почніть зіставляти розклади з часовими позначками.

Завдання 12: Використайте perf, щоб перевірити, куди йде CPU-час (коли неочевидно)

cr0x@server:~$ sudo perf top -p 22891
Samples: 2K of event 'cpu-clock', Event count (approx.): 2000000000
  35.12%  updatedb   libc.so.6        [.] __memmove_avx_unaligned_erms
  22.40%  updatedb   libz.so.1        [.] deflate_slow
  10.08%  updatedb   updatedb         [.] hash_path

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

Рішення: Зменште обсяг даних для сканування, знизьте частоту, додайте обмеження cgroup або перемістіть роботу з машини.

Завдання 13: Знайдіть, який юніт запустився нещодавно (швидкий journal grep)

cr0x@server:~$ sudo journalctl -S "12:00:00" -U "12:01:00" -g "Started " --no-pager
Feb 05 12:00:01 server systemd[1]: Started Update a database for mlocate.
Feb 05 12:00:10 server systemd[1]: Started Rotate log files.

Значення: Це найшвидший «що щойно стартувало?» вигляд, коли ви можете обмежити час піку.

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

Завдання 14: Безпечно обмежити systemd-сервіс (override через drop-in)

cr0x@server:~$ sudo systemctl edit updatedb.service
# (creates a drop-in override)
cr0x@server:~$ sudo cat /etc/systemd/system/updatedb.service.d/override.conf
[Service]
Nice=10
CPUQuota=20%
IOSchedulingClass=best-effort
IOSchedulingPriority=7
cr0x@server:~$ sudo systemctl daemon-reload
cr0x@server:~$ sudo systemctl restart updatedb.service

Значення: Ви не «вирішили» проблему updatedb; ви просто зробили так, щоб він не діставляв інші процеси хоста.

Рішення: Використовуйте троттлінг як міру пом’якшення, а потім зробіть реальне виправлення: перенесення розкладу, життер і зменшення області сканування.

Завдання 15: Додати життер до таймера (зупинити флотне натовпіння)

cr0x@server:~$ sudo systemctl edit updatedb.timer
cr0x@server:~$ sudo cat /etc/systemd/system/updatedb.timer.d/override.conf
[Timer]
RandomizedDelaySec=180
cr0x@server:~$ sudo systemctl daemon-reload
cr0x@server:~$ sudo systemctl restart updatedb.timer

Значення: Завдання все ще виконується, але не одночасно по всьому флоту і не рівно на хвилину.

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

Cron vs systemd timers vs “агенти”: як вони насправді поводяться

Нам не потрібні релігійні війни про планувальники. Потрібна правильна модель у голові.

Cron: простий, всюдисущий і легкий для випадкового дублювання

Cron виконує команди за розкладом. І все. Його простота — причина, чому він досі скрізь — і чому його використовують як смітник для «тимчасових» скриптів, що живуть п’ять років.

Де cron ховає роботу:

  • Системний crontab: /etc/crontab
  • Директорії-дропіни: /etc/cron.d/, /etc/cron.hourly/, /etc/cron.daily/ тощо.
  • Користувацькі crontab’и: у /var/spool/cron або /var/spool/cron/crontabs

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

systemd timers: видиміші, потужніші й здатні дивувати

Таймери — об’єкти першого класу в systemd. Вони мають логи. Вони мають статус. Вони можуть надолужувати після простою. Вони можуть додавати життер. Вони можуть мати вікна точності, що трохи відстрочують спрацьовування, щоб коалесцентувати wakeup-и.

Класичний режим відмови таймерів — persistent + boot storms. Після обслуговування, перезавантаження або подій автоскейлінгу багато пропущених таймерів можуть спрацювати одразу. Якщо кожен таймер «малий», сумарне навантаження — ні.

Агенти: «ми запускаємось кожні 5 хвилин» — це не контракт, це загроза

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

Діагностична хитрість — шукати:

  • Регулярні сплески CPU в одному демоновому процесі.
  • Регулярні сплески дочірніх процесів, які вилучаються цим демоном.
  • Повторювані записи в логах кожні N хвилин.

Кут зору збереження даних: піки CPU від I/O, приховані під виглядом CPU

Як інженер зі збереження даних, скажу прямо: багато «піків CPU» — це технічні роботи диска в костюмі CPU.

Огляди метаданих — це робота CPU

Завдання на кшталт updatedb, антивірусних сканувань, перелічення файлів для бекапу та інструментів цілісності виконують масивні обходи директорій. Навіть якщо диски швидкі, перетворення мільйонів dentries та inode’ів у список коштує CPU. На файлових системах через мережу гірше: кожен виклик метаданих — мережевий круговий запит плюс клієнтська обробка й кешування.

Стиснення й контрольні суми — це робота CPU

Якщо ви ввімкнули стиснення «щоб заощадити місце», вітаю: ви також підписалися платити CPU за кожний запис (а іноді й за читання). Багато інструментів резервного копіювання стискають за замовчуванням. Потоки логшипінгу стиснують. Навіть logrotate може стиснути архіви. Ці завдання часто прив’язані до часу й створюють сплески.

TRIM та scrub не безкоштовні

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

Шифрування передбачуване — і піки при запусках

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

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

Три корпоративні міні-історії (з життя)

Міні-історія 1: Інцидент через хибне припущення («Ми не використовуємо cron»)

Середня компанія мала набір API-серверів за балансувальником навантаження. Кожні п’ять хвилин відсоток помилок трохи піднімався. Не повний збій — але достатньо, щоб SLO повільно «витікав». Першою думкою на чергуванні був звичний підозрюваний: garbage collection або шумний сусід на гіпервізорі.

Перевірили логи застосунку — нічого. Перевірили деплойти — нічого. Перевірили «cron» — в crontab -l не знайшли нічого релевантного. З упевненістю оголосили: «На цих машинах cron не використовується». Розслідування вилилось у профілювання ендпойнтів і тонке налаштування пулів потоків.

Прорив стався, коли хтось порівняв часові мітки піків CPU з systemctl list-timers. Там був updatedb.timer, що запускався кожні п’ять хвилин, з persistent і без життеру. Він прийшов із базового образу ОС, який «захардений», але забув документувати ввімкнені таймери.

Чому це вплинуло на API? Сервери також хостили контейнерні рантайми. Сканування updatedb обходило величезні дерева overlay. Це не лише використовувало CPU; воно трясло page cache і кеш метаданих. Застосунок трохи сповільнювався, потім приходив у норму — знову й знову, як маленька DDoS-атака зсередини.

Виправлення були нудними: відключити updatedb на цих хостах і ввести політику, що базові образи мають документувати увімкнені таймери. Постмортем не про locate. Він про припущення. «Немає cron» не означає «немає запланованих завдань». Це означає «ми не дивилися в правильний планувальник».

Міні-історія 2: Оптимізація, що обернулась проти (сжаття всюди)

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

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

Що сталося насправді: стиснення невеликих партій кожні 15 хвилин викликало постійні сплески CPU замість однієї передбачуваної нічної роботи. Ці сплески збігались з іншими таймерами платформи — logrotate, компактація метрик, перевірки оновлень — і створили постійний «зайнятий хвилинний» патерн. Система не була перевантажена в середньому; вона була перевантажена повторюваними короткими хвилинами.

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

Міні-історія 3: Скучна практика, що врятувала день (життер і бюджети)

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

Кожне нове заплановане завдання мало декларувати: частоту, очікуваний час виконання, приблизний CPU-профіль і чи може його відкласти. Завдання додавалися як systemd timers з життером за замовчуванням. Вони використовували RandomizedDelaySec для всього неважливого і уникали планування на початок години.

Якось розгорнули оновлення агента відповідності, що виявилося важчим, ніж очікувалося. Він робив інвентаризацію файлової системи і криптографічну верифікацію. CPU зріс — але він не здивував флот. Чому? Таймер мав 10‑хвилинний розклад з 6‑хвилинним випадковим зсувом, а сервіс мав CPU‑квоту. Робота розтяглась. Балансувальники не побачили синхронізованого провалу.

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

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

Тут більшість команд марнують години. Не робіть цього.

1) Піки кожні 5 хвилин, «немає cron-завдань», нічого в логах застосунку

  • Симптом: CPU стрибає до 80–100% кожні 5 хвилин. Латентність застосунку підвищується. У логах застосунку нічого очевидного.
  • Корінь: systemd таймер (часто updatedb.timer, таймери агентів, таймери перевірки пакетів) або демон, що прокидається періодично.
  • Виправлення: systemctl list-timers --all, зіставити з journalctl, додати життер або відключити некритичні таймери; закапати CPU через drop-in override.

2) Піки в :00 на багатьох хостах (флот-синхронізація)

  • Симптом: Весь кластер бачить піки CPU на початку години; downstream сервіси фіксують p95-зростання латентності.
  • Корінь: синхронізовані розклади (cron або таймери без RandomizedDelaySec), часто через ідентичні конфіги образів.
  • Виправлення: додати життер, рознести розклади, використовувати точність таймера і RandomizedDelaySec; уникати «minute 0» конвенцій.

3) Піки CPU збігаються з навантаженням диска, але CPU виглядає винуватцем

  • Симптом: Підвищення CPU, але також росте %iowait; тривоги по латентності диска; потоки застосунку блокуються.
  • Корінь: заплановані I/O‑важкі роботи (logrotate compress, бекап, scrub/trim), що запускають CPU‑роботу (сжаття, контрольні суми) і насичують черги збереження.
  • Виправлення: перенести I/O‑роботи в непіковий час; зменшити паралельність; використовувати ionice/IOSchedulingClass; перевірити здоров’я та глибину черги збереження.

4) Піки з’явилися після ввімкнення «сканування безпеки» або «інвентарю»

  • Симптом: періодичні сплески CPU, багато короткоживучих процесів, часті stat-виклики файлової системи.
  • Корінь: EDR/агент відповідності ходить по файловій системі, хешує бінарі, сканує контейнери.
  • Виправлення: налаштуйте виключення (директорії контейнерів, кеші збірки), зменшіть частоту сканувань, домагайтесь від вендора режиму з меншим навантаженням; при потребі ізолюйте на виділених вузлах.

5) Піки з’являються тільки після перезавантаження або простою

  • Симптом: Після завантаження здається, що все гаразд, але за кілька хвилин CPU починає різко підскакувати кілька разів підряд.
  • Корінь: systemd timers з Persistent=true «надолужують» пропущені виконання; багато пропущених таймерів виконується при завантаженні.
  • Виправлення: додайте RandomizedDelaySec, перегляньте налаштування Persistent і переконайтесь, що критичні сервіси при завантаженні не конкурують з технічними роботами.

6) Піки зникають, коли ви запускаєте роботу вручну «для тесту»

  • Симптом: Ви запускаєте підозрілий скрипт вручну і він виглядає нормально; піки все одно відбуваються пізніше.
  • Корінь: середовище запланованого виконання відрізняється: інший PATH, інший nice/ionice, інші аргументи, інша робоча директорія, або воно запускається одночасно з іншими задачами.
  • Виправлення: зафіксуйте точну командну лінію й середовище з systemd unit або логів cron; відтворіть з тими самими параметрами і з тією самою конкуренцією.

Контрольні списки / покроковий план

Контрольний список A: Окремий хост з періодичними піками

  1. Запишіть каденс піків (кожні 5 хвилин? у :00?).
  2. Зловіть найактивніші процеси під час піку (pidstat або top -H).
  3. Перевірте режим CPU (mpstat) і чергу виконання (vmstat).
  4. Перелічіть systemd timers і зіставте часові мітки (systemctl list-timers --all).
  5. Перелічіть джерела cron (/etc/cron.d, crontab -l для ключових користувачів).
  6. Зіставте з логами (journalctl навколо часу піку).
  7. Підтвердіть юніт/cgroup гарячого PID (/proc/PID/cgroup).
  8. Пом’якшіть безпечно (CPUQuota/Nice, додати життер, перенести розклад).
  9. Виправте корінь (виключити шляхи, зменшити частоту, видалити дублікати).
  10. Перевірте принаймні 3 інтервали піків за допомогою sar або вашого моніторингу.

Контрольний список B: Флот-синхронізовані піки

  1. Підтвердіть синхронізацію на кількох вузлах (та сама хвилина, та сама форма піку).
  2. Виявте загальні таймери, увімкнені в базовому образі (systemctl list-timers на кількох вузлах).
  3. Шукайте вендорні агенти, розгорнуті скрізь (інвентар/EDR/бекап).
  4. Застосуйте життер скрізь для некритичних задач.
  5. Встановіть CPU‑бюджети для фонової роботи (cgroups через systemd override).
  6. Рознесіть важкі завдання за ролями (наприклад, різні розклади для веб‑ і db‑вузлів).
  7. Перевірте латентність і кількість помилок після змін.

Контрольний список C: Коли винуватець — «робота збереження», а не «CPU»

  1. Перевірте iowait і використання диска під час піків.
  2. Визначте завдання, що роблять стиснення/хешування (бекап, logrotate, сканери).
  3. Перенесіть важке стиснення поза хост або в непіковий час, якщо можливо.
  4. Тротлінгуйте I/O для фонівих задач (ionice або налаштування I/O в systemd).
  5. Запобігайте обходам директорій у контейнерних і кешових шляхах.

Цікаві факти й історія, які мають значення в продакшені

  • Факт 1: Дизайн cron походить з раннього Unix; його поведінка «запуск точно на хвилину» — одна з причин, чому флот все ще збігається в :00.
  • Факт 2: systemd timers можуть бути persistent, тобто запускають пропущені завдання після простою — корисно для ноутбуків, ризиковано для серверів.
  • Факт 3: Багато дистрибутивів мігрували класичні cron‑завдання (наприклад, logrotate) на systemd timers, тому «ми перевірили cron» перестало бути достатнім роками тому.
  • Факт 4: База даних updatedb/locate існує, щоб робити пошук файлів швидким — корисно на dev‑машинах, часто даремно на продакшен‑серверах.
  • Факт 5: logrotate може стиснути оберненi логи, а стиснення важке для CPU; один великий лог може створити більший пік, ніж кілька маленьких.
  • Факт 6: TRIM (fstrim) зазвичай запланований раз на тиждень на багатьох Linux; на деяких бекендах збереження це може створювати помітні сплески.
  • Факт 7: Періодичні піки легше діагностувати, ніж постійне навантаження, бо їх можна зіставити з метаданими планувальника — якщо ви дійсно подивитесь.
  • Факт 8: Випадкова затримка (життер) існує саме для того, щоб запобігти thundering herds; не використовувати її у флоті — уникана самоприниження.
  • Факт 9: Багато «агентів» мають власні внутрішні розклади й можуть не показуватися у cron/timers взагалі, тож треба спостерігати за їхньою поведінкою CPU напряму.

FAQ

1) Що перевірити в першу чергу при періодичних піках CPU?

systemd timers: systemctl list-timers --all. Це найшвидший спосіб впіймати ОС‑технічні роботи й таймери вендорів, про які забули.

2) Я перевірив cron і нічого не знайшов. Що далі?

Перевірте systemd timers, потім шукайте довгоживучі демони (агенти), що прокидаються періодично. Зіставте з journalctl у часі піку.

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

Бо хтось встановив */5 * * * * у cron або OnCalendar=*:0/5 у таймері. Комп’ютери буквальні. Людям подобаються круглі числа.

4) Мені просто вимкнути той таймер?

Іноді так (наприклад, updatedb на продакшен‑сервері). Іноді ні (сканування безпеки, бекапи). Краще: зменшити частоту, додати життер, виключити важкі шляхи і накласти ліміти CPU.

5) Як довести, що таймер — причина, а не просто кореляція?

Зіставте LAST час запуску таймера з часовою позначкою піку, потім перевірте старт юніту в journalctl і підтвердіть, що гарячий PID належить цьому юніту через cgroup.

6) Пік здебільшого у %sys (system CPU). Що це підказує?

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

7) Чому піки погіршилися після перезавантаження?

Показники з persistent таймерів можуть «надолужувати» пропущені запуски після простою. Кілька пропущених завдань можуть виконуватися одразу після завантаження й накладати навантаження.

8) Як зупинити синхронізовані піки по всьому флоту?

Додайте життер (RandomizedDelaySec) і уникайте планування всього на :00. Для важких завдань накладайте CPU‑квоти, щоб фонові роботи не могли задушити сервіс.

9) Чи може збереження викликати піки CPU, навіть якщо диски «в порядку»?

Так. Обходи директорій, контрольні суми, стиснення і шифрування — це робота CPU, запущена завданнями, пов’язаними із збереженням. «Диск в порядку» не означає «немає роботи, пов’язаної із збереженням».

10) Що робити, якщо ім’я процесу нефункціональне, наприклад «python»?

Витягніть повну командну лінію (ps -p PID -o cmd), перевірте батьківський процес і членство в cgroup. Якщо це systemd‑юніт, systemctl status UNIT часто покаже шлях до скрипта.

Висновок: практичні наступні кроки

Якщо ваші піки CPU періодичні — дійте як SRE, а не ворожка. Ставтеся до цього як до запланованої роботи, поки не матимете доказів протилежного.

  1. На одному хості: зловіть гарячий процес під час піку за допомогою pidstat, потім зв’яжіть його з юнітом або записом cron.
  2. На рівні планувальника: спочатку переліть systemd timers, потім cron. Шукайте каденси кожні 5 хвилин і на початку години.
  3. Пом’якшіть безпечно: обмежте через systemd drop-ins (CPUQuota/Nice) і додайте життер, щоб зупинити синхронні флот‑піки.
  4. Виправте корінь: виключіть важкі шляхи, зменшіть частоту, видаліть дублікати розкладів і не запускайте зручності розробників на продакшен‑серверах.
  5. Перевірте: спостерігайте принаймні кілька інтервалів і підтвердіть, що пік зник — або принаймні більше не впливає на ваш бюджет латентності.

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

← Попередня
Фаєрвол Linux: чиста структура nftables, що залишається зрозумілою при 500 правилах
Наступна →
DNS: split‑horizon, коли все йде не так — виправлення, яке зупиняє хаос «всередині/зовні»

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