Debian 13: NTP працює, але дрейф залишається — налаштування апаратного годинника та chrony (Випадок №19)

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

Chrony каже, що ви синхронізовані. Моніторинг усе одно кричить «зсув годинника». Kerberos час від часу відмовляє квитки. TLS-з’єднання падають, ніби це знову 2012 рік. І після кожного перезавантаження сервер «телепортується» на кілька секунд (або хвилин) від реальності.

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

Практична модель у голові: хто керує часом?

Підтримка часу в Linux — це тристоронні взаємини:

  • Системний годинник (час ядра): той, який використовують ваші процеси. Саме він важливий для логів, сертифікатів, таймаутів і розподілених систем.
  • Апаратний годинник (RTC): маленький годинник на материнській платі з батарейкою. Грубий. Дрейфує. Зберігає час при відключенні живлення. Не є автоматично правильним.
  • Синхронізатор: chrony (в цьому випадку) вирішує, як керувати системним годинником на основі джерел часу та правил (slew vs step, пороги, офсети, стабільність).

Патерн відмов «NTP працює, але дрейф зберігається» зазвичай один із таких:

  • RTC помилковий — і ви читаєте його при завантаженні (або після відновлення зі сну), знову інфікуючи системний годинник неправильним часом.
  • Chrony синхронізує, але обмежений у повільному slewing, тоді як системний годинник постійно потягнутий іншою стороною (хост VM, проблемний TSC, інший сервіс часу).
  • Chrony синхронізується з неправильним джерелом (локальне джерело, нестабільний апстрім, або воно ізольоване мережею) і залишається «щасливим», поки ви дрейфуєте від істинного часу.

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

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

Швидкий план діагностики (перевірте 1/2/3)

Якщо у вас є лише 10 хвилин до того, як канал інцидентів стане гарячим, виконайте це в порядку.

1) Чи тільки chrony керує системним годинником?

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

2) Чи стабільний системний годинник і чи відбуваються стрибки (step)?

Великі стрибки вказують на step-корекції (або зовнішні скиди), а не на дрейф. Дрейф означає стабільну, але неправильну частоту. Виправлення різні.

3) Чи отруює вас RTC при завантаженні/відновленні?

Якщо машина правильна після тривалого часу роботи, але невірна відразу після перезавантаження — підозрюйте RTC та налаштування UTC/localtime, а не ваші NTP-сервери.

4) Чи якісне джерело часу?

Chrony охоче обирає «доступне», але нестабільне джерело. Вам потрібні низький jitter, низька дисперсія та розумний stratum (більшість часу).

5) Визначте політику: тільки slew чи дозволяти step?

Продакшен-системам часто потрібні контрольовані step-перевірки при завантаженні (або після довгих простоїв) і slewing в робочому стані. Налаштовуйте це явно.

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

  1. NTP походить з початку 1980-х, створений для світу з повільнішими мережами та набагато гіршими годинниками, ніж сьогодні.
  2. Linux розрізняє «час» і «частоту»: підпорядкування годинника означає виправлення і поточного офсету, і швидкості його ходу.
  3. RTC-чіпи — не точні прилади. Багато з них — дешеві осцилятори, чий дрейф змінюється з температурою та віком.
  4. UTC vs localtime в RTC — культурна війна: Linux за замовчуванням використовує UTC; Windows історично вважає за краще localtime. Машини з подвійним завантаженням страждають через це.
  5. Існують високосекунди, бо Земля не завжди чемна: іноді цивільний час додає секунду.
  6. Chrony створено для кращої поведінки при переривчастих мережах, як у ноутбуків або систем, що не можуть постійно тримати доступність NTP.
  7. Системи обліку часу в ядрі змінилися з появою сучасних CPU: стабільність TSC, invariant TSC та вибір clocksource впливають на дрейф.
  8. Раніше віртуалізація була кошмаром для часу: старі гіпервізори відкривали нестабільні лічильники циклів, спричиняючи дрейф або стрибки в гостях.
  9. PPS (Pulse Per Second) з GPS може забезпечити дисципліну субмікросекундного рівня за правильного налаштування, що робить NTP по WAN схожим на вгадайку.

Інструменти та терміни, які вам справді потрібні

Вам не потрібен PhD. Вам потрібні правильні окуляри:

  • Offset: наскільки ваш системний годинник відрізняється від джерела прямо зараз.
  • Frequency / skew: як швидко ваш годинник біжить відносно реального часу; chrony це коригує.
  • Step: миттєво перемістити годинник (добре для корекції при завантаженні, погано для деяких навантажень).
  • Slew: повільно прискорювати або сповільнювати годинник, поки не зрівняється (безпечно для більшості навантажень, але повільно при великому відхиленні).
  • RTC: апаратний годинник, який ви читаєте/записуєте через hwclock.
  • Kernel clocksource: що ядро використовує для відліку часу (TSC, HPET, ACPI PM timer тощо). Поганий вибір може дрейфувати.

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

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

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

Завдання 1: Підтвердьте стек часу (systemd + chrony)

cr0x@server:~$ timedatectl
               Local time: Mon 2025-12-30 11:12:03 UTC
           Universal time: Mon 2025-12-30 11:12:03 UTC
                 RTC time: Mon 2025-12-30 11:10:41
                Time zone: Etc/UTC (UTC, +0000)
System clock synchronized: yes
              NTP service: active
          RTC in local TZ: no

Значення: «System clock synchronized: yes» необхідно, але недостатньо. Цікавими рядками є RTC time і RTC in local TZ.

Рішення: Якщо RTC відрізняється більше ніж на секунду-дві, плануйте виправлення дисципліни RTC (див. пізніші завдання). Якщо «RTC in local TZ: yes» на сервері — ймовірно, варто перейти на UTC, якщо немає причини для подвійного завантаження.

Завдання 2: Переконайтесь, що chrony дійсно є NTP-двигуном

cr0x@server:~$ systemctl status chrony --no-pager
● chrony.service - chrony, an NTP client/server
     Loaded: loaded (/lib/systemd/system/chrony.service; enabled; preset: enabled)
     Active: active (running) since Mon 2025-12-30 09:10:22 UTC; 2h 1min ago
       Docs: man:chronyd(8)
             man:chronyc(1)
   Main PID: 712 (chronyd)
      Tasks: 1 (limit: 38219)
     Memory: 3.2M
        CPU: 1.821s
     CGroup: /system.slice/chrony.service
             └─712 /usr/sbin/chronyd -F 1

Значення: Chronyd запущено. Параметр «-F 1» показує, що він використовує корекцію частоти з даних дрейфу з самого початку.

Рішення: Якщо chrony не активний — виправте це насамперед. Якщо активний, перевірте на конфлікти далі.

Завдання 3: Виявлення конфліктів служб часу (timesyncd, ntpd, vendor agents)

cr0x@server:~$ systemctl list-units --type=service | egrep -i 'chrony|timesync|ntp|openntpd'
chrony.service                      loaded active running chrony, an NTP client/server
systemd-timesyncd.service           loaded active running Network Time Synchronization

Значення: У вас запущено systemd-timesyncd разом із chrony. Класична дуель за кермо.

Рішення: Вимкніть timesyncd, якщо chrony є обраним авторитетом.

cr0x@server:~$ sudo systemctl disable --now systemd-timesyncd.service
Removed "/etc/systemd/system/sysinit.target.wants/systemd-timesyncd.service".

Значення: timesyncd зупинено і не повернеться при завантаженні.

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

Завдання 4: Перевірте стан синхронізації в chrony (tracking)

cr0x@server:~$ chronyc tracking
Reference ID    : 192.0.2.10 (ntp1.example.net)
Stratum         : 3
Ref time (UTC)  : Mon Dec 30 11:12:00 2025
System time     : 0.000214567 seconds slow of NTP time
Last offset     : -0.000180123 seconds
RMS offset      : 0.000355901 seconds
Frequency       : 18.421 ppm slow
Residual freq   : -0.012 ppm
Skew            : 0.098 ppm
Root delay      : 0.012345678 seconds
Root dispersion : 0.001234567 seconds
Update interval : 64.0 seconds
Leap status     : Normal

Значення: Система приблизно на ~214 мікросекунд відстає. Гаразд. Але зверніть увагу на Frequency 18.421 ppm slow: ваш годинник втрачає близько ~1.6 секунди за добу без корекції.

Рішення: Якщо частота велика (наприклад >100 ppm) або skew величезний — підозрюйте нестабільний clocksource або віртуалізацію. Якщо офсети малі, але ваші додатки скаржаться на зсув, можливо, відбуваються стрибки/скачки часу (Завдання 7/8).

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

cr0x@server:~$ chronyc sources -v
  .-- Source mode  '^' = server, '=' = peer, '#' = local clock.
 / .-- Source state '*' = current best, '+' = combined, '-' = not combined,
| /   '?' = unreachable, 'x' = time may be in error, '~' = too variable.
||                                                 .- xxxx [ yyyy ] +/- zzzz
||      Reachability register (octal)              |  xxxx = adjusted offset,
||      Log2(Polling interval)                     |  yyyy = measured offset,
||                                                 |  zzzz = estimated error.
||                                                 |
MS Name/IP address         Stratum Poll Reach LastRx Last sample
===============================================================================
^* ntp1.example.net              2   6   377    21   -180us[ -220us] +/-  900us
^+ ntp2.example.net              2   6   377    19   +120us[  +80us] +/- 1100us
^- 203.0.113.44                  3   6   377    17   +980us[ +950us] +/- 5500us

Значення: У вас є переважне джерело (^*) і комбіноване резервне (^+). Третє джерело не комбіноване (^-), ймовірно через гірші межі помилки.

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

Завдання 6: Переконайтесь, що ядро не «тоне» в корекціях часу

cr0x@server:~$ chronyc activity
200 OK
1 sources online
0 sources offline
0 sources doing burst (return to online)
0 sources doing burst (return to offline)
0 sources with unknown address

Значення: Chrony бачить стабільну доступність джерел. Добре.

Рішення: Якщо джерела часто офлайн — спочатку виправте мережу/фаєрвол, перед налаштуванням chrony.

Завдання 7: Знайдіть свідчення стрибків часу (stepping)

cr0x@server:~$ journalctl -u chrony --since "24 hours ago" --no-pager | egrep -i 'step|slew|makestep|System clock wrong'
Dec 30 09:10:22 server chronyd[712]: System clock wrong by -3.842311 seconds, adjustment started
Dec 30 09:10:22 server chronyd[712]: System clock was stepped by -3.842311 seconds

Значення: Chrony зробив step годинника при запуску сервісу. Це нормально, якщо відбувається лише на завантаженні і в межах очікуваного порогу.

Рішення: Якщо стрибки відбуваються в робочі години, налаштуйте політику makestep (далі), або знайдіть зовнішнього актора, що примушує step (інструменти VM, скрипти адміністраторів, помилки читання RTC).

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

cr0x@server:~$ cat /sys/devices/system/clocksource/clocksource0/current_clocksource
tsc
cr0x@server:~$ cat /sys/devices/system/clocksource/clocksource0/available_clocksource
tsc hpet acpi_pm

Значення: Ви використовуєте TSC. Зазвичай це добре на сучасних CPU з invariant TSC. На деяких платформах (або певних конфігураціях віртуальних машин) це може спричиняти проблеми.

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

Завдання 9: Перевірте сам RTC і порівняйте із системним часом

cr0x@server:~$ sudo hwclock --show
2025-12-30 11:10:41.123456+00:00
cr0x@server:~$ date -u
Mon Dec 30 11:12:07 UTC 2025

Значення: RTC відстає приблизно на 86 секунд. Якщо ви зараз перезавантажитеся, ймовірно, під час старту опинитеся позаду, а потім chrony виправить час.

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

Завдання 10: Підтвердіть, чи RTC вважається UTC або localtime

cr0x@server:~$ timedatectl show -p RTCInLocalTZ -p Timezone -p LocalRTC
RTCInLocalTZ=no
Timezone=Etc/UTC
LocalRTC=no

Значення: RTC — UTC. Це здоровий стандарт для серверів.

Рішення: Якщо RTCInLocalTZ=yes і ви не використовуєте подвійне завантаження, змініть це (Завдання 11). Якщо ви дійсно використовуєте подвійне завантаження — вирішіть, хто «перемагає», і документуйте це.

Завдання 11: Встановіть RTC в UTC (звичайна серверна практика)

cr0x@server:~$ sudo timedatectl set-local-rtc 0 --adjust-system-clock

Значення: ОС відтепер трактуватиме RTC як UTC і може відрегулювати системний час, щоб зберегти локальний час незмінним.

Рішення: Виконуйте це у вікні обслуговування, якщо системний годинник може зробити step. Потім запишіть коректний системний час у RTC (Завдання 12), коли chrony стабільний.

Завдання 12: Запишіть виправлений системний час у RTC (одноразове очищення)

cr0x@server:~$ chronyc waitsync 30
200 OK
cr0x@server:~$ sudo hwclock --systohc --utc

Значення: waitsync гарантує, що chrony синхронізувався перед тим, як ви зробите знімок часу в RTC. --systohc записує системний час у RTC.

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

Завдання 13: Підтвердіть політику step/slew в chrony (робіть її явною)

cr0x@server:~$ grep -v '^\s*#' /etc/chrony/chrony.conf | sed '/^\s*$/d'
pool ntp.example.net iburst maxsources 4
driftfile /var/lib/chrony/chrony.drift
rtcsync
makestep 1.0 3
keyfile /etc/chrony/chrony.keys
leapsectz right/UTC
logdir /var/log/chrony

Значення: makestep 1.0 3 означає: зробити step, якщо офсет > 1 секунди, але лише в перші 3 оновлення. Це розумна стратегія «виправити при завантаженні, потім slewing». rtcsync тримає RTC приблизно в лінії.

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

Завдання 14: Перевірте пошкодження часу при suspend/resume (ноутбуки, деякі сервери)

cr0x@server:~$ journalctl --since "7 days ago" --no-pager | egrep -i 'suspend|resume|PM: suspend|PM: resume'
Dec 29 18:44:02 server kernel: PM: suspend entry (deep)
Dec 29 19:12:19 server kernel: PM: suspend exit

Значення: Якщо це ноутбук або сервер з агресивним енергозбереженням, resume може спричиняти розриви часу в залежності від платформи/прошивки.

Рішення: Якщо після resume з’являються сплески зсуву — розгляньте більш жорстку політику step після resume (hook перезапуску сервісу), або вимкніть глибокий suspend на системах, яким потрібен суворий час.

Завдання 15: Перевірте, чи хтось вручну не змінював час (серйозно)

cr0x@server:~$ journalctl --since "48 hours ago" --no-pager | egrep -i 'set time|time has been changed|CLOCK_SET|adjtimex'
Dec 30 10:03:11 server systemd[1]: Time has been changed

Значення: Хтось або щось ініціювало зміну часу. Це могло бути chrony step, адміністратор або інший агент.

Рішення: Корелюйте часові мітки з логами chrony (Завдання 7). Якщо це не chrony — шукайте винуватця: CM-скрипти, інструменти гіпервізора або власноручні скрипти.

Налаштування chrony, що дійсно змінюють результати

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

Makestep: контролюйте, коли дозволений step

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

Що я роблю на більшості Debian-серверів:

  • Дозволяю step рано після завантаження, з низьким порогом.
  • Після цього — тільки slew-корекції.

Приклад політики (зазвичай в Debian за замовчуванням, але перевірте):

cr0x@server:~$ sudo bash -lc 'printf "%s\n" "makestep 1.0 3" | tee /etc/chrony/conf.d/10-makestep.conf'
makestep 1.0 3

Значення: Робіть step лише якщо офсет більше за 1 секунду і лише в перші три оновлення.

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

rtcsync проти відстеження дрейфу RTC: розумійте, що ви купуєте

rtcsync наказує chronyd періодично копіювати системний час у RTC (через режим ядра 11-хвилинного інтервалу). Це допомагає тримати RTC достатньо близько, щоб при перезавантаженні системний час не був дуже неправильним.

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

  • Покращення середовища RTC (оновлення прошивки, вимкнення дивних енергозберігаючих функцій).
  • Використання стабільного джерела часу (локальні NTP-сервери, PTP в деяких середовищах).
  • Для суворих систем — локальний еталон (PPS, GPS) і жорстка стратегія holdover.

Інтервал опитування та burst-поведінка: не соромтеся на старті

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

Для рядка pool:

cr0x@server:~$ grep -R "^\s*pool\|^\s*server" /etc/chrony
/etc/chrony/chrony.conf:pool ntp.example.net iburst maxsources 4

Значення: Використовується pool (DNS з ротацією) з максимум 4 джерелами. Це прийнятно.

Рішення: Для продакшену віддавайте перевагу кільком стабільним внутрішнім джерелам, якщо вони є; інакше — кільком зовнішнім джерелам з розумними правилами фаєрволу (UDP 123) та гарним DNS.

Локальний stratum та «я буду своїм годинником»: не робіть цього

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

Якщо бачите директиви local stratum, зупиніться і спитайте навіщо. Більшість середовищ не повинні цього робити, окрім свідомо спроектованого резерву.

Апаратний годинник і hwclock: зробіть його нудним

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

Як виглядає «RTC помилковий»

  • Час правильний після кількох годин роботи, але невірний відразу після перезавантаження.
  • Час відхиляється на постійну величину після кожного втручання живлення.
  • Машини з подвійним завантаженням показують точно годину помилки під час переходів DST (невідповідність localtime/UTC).

Припиніть неконтрольовані записи в RTC

Деякі адміністратори запускають cron на кшталт «hwclock –systohc кожну хвилину». Це перетворює записи RTC на шум і підвищує ризик запису неправильного часу під час транзієнту синхронізації. Якщо ви записуєте в RTC, робіть це після підтвердження синхронізації і не постійно.

Виміряйте швидкість дрейфу RTC (щоб вибрати політику)

Ви можете кількісно оцінити дрейф без спеціальних інструментів. Зробіть так:

  1. Синхронізуйте системний час через chrony.
  2. Запишіть системний час у RTC один раз.
  3. Після 24 годин порівняйте RTC із системним часом знову (без запису).

Команди для кроку порівняння:

cr0x@server:~$ sudo hwclock --show
2025-12-31 11:11:12.000000+00:00
cr0x@server:~$ date -u
Tue Dec 31 11:12:07 UTC 2025

Значення: RTC відстає приблизно на 55 секунд за ~24 години — це серйозно. Це не проблема налаштування chrony; це апаратна/прошивкова або платформи проблема.

Рішення: Для такого рівня дрейфу покладайтеся на дисципліну NTP і вважайте RTC лише як «запусковий» механізм, поки ви досліджуєте оновлення BIOS, проблеми з материнською платою або заміну апаратури, якщо це важливо.

Віртуалізація та ноутбуки: фабрики дрейфу

На «голому» металевому сервері з стабільними clocksource chrony зазвичай сходиться і залишається нудним. Віртуальні машини та ноутбуки додають хаос:

  • Агенти синхронізації часу VM можуть робити step годинника у гості за спиною у chrony.
  • Зміна частоти CPU і стани сну можуть змінювати поведінку осцилятора і стабільність таймінгу.
  • Перевантаження хоста може затримувати планування vCPU, через що час виглядає «відсталим», а потім наздоганяє.

Виявіть VM і перевірте функції гіпервізора для часу

cr0x@server:~$ systemd-detect-virt
kvm

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

Рішення: Якщо ви запускаєте guest-агенти, що синхронізують час, або їх вимкніть, або налаштуйте так, щоб вони не боролися з chrony.

Перевірка стану дисципліни часу в ядрі (стан NTP ядра)

cr0x@server:~$ timedatectl timesync-status
       Server: 192.0.2.10 (ntp1.example.net)
Poll interval: 1min 4s (min: 32s; max 34min 8s)
         Leap: normal
      Version: 4
      Stratum: 3
    Reference: 9C00020A
    Precision: 1us (-20)
Root distance: 1.652ms (max: 5s)
       Offset: -214us
        Delay: 1.233ms
       Jitter: 211us

Значення: Навіть якщо хост-клієнт — chrony, systemd усе одно може показувати стан дисципліни NTP у ядрі. Це дає інший погляд на офсет/джиттер.

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

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

Три корпоративні міні-історії (як це ламається в реальному житті)

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

Компанія керувала флотом Debian-подібних API-нод за балансувальником. Все виглядало нормально: низька латентність, мало помилок. Потім під час ротації сертифікатів невелика частина вузлів почала провалювати вихідні TLS-з’єднання з «certificate not yet valid». Збої не були однорідні; вони приходили хвилями.

Інженер на чергуванні перевірив chrony і побачив, що він синхронізований. Це здавалося доказом відсутності проблем з часом. Вони ескалували на мережу та PKI, бо «NTP в порядку». Це припущення стало пасткою: «синхронізований» неправильно інтерпретували як «стабільний».

Справжня причина була при завантаженні: RTC на деяких хостах тримався в localtime через артефакт образу з подвійним завантаженням для тестового обладнання. Після перезавантаження ті ноди ставали на кілька хвилин позаду, а потім chrony крокував їх назад у норму за кілька оновлень. Між стартом і стабілізацією TLS-вікна дійсності кусали їх.

Виправлення було простим. Стандартизували RTC на UTC, вимкнули другий сервіс часу, що інколи боровся з chrony, і додали перевірку здоров’я: вузли не потрапляли до пулу балансувальника, поки chronyc waitsync не пройде.

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

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

Команда з оптимізації хотіла швидші завантаження і менше фону. Вони помітили, що chrony інколи робив початковий burst і step при старті. Це виглядало «безладно». Хтось вирішив прибрати iburst і повністю заборонити step — тільки slew, завжди. Це здавалося елегантним. Час має бути плавним, правда?

На здорових вузлах це працювало. Потім частина машин провела вихідні в стояку з неправильно налаштованим топового комутатора. Два дні без доступності NTP. Коли мережу відновили, сервери були на десятки секунд позаду.

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

Вони повернули розумну політику makestep: step лише рано в процесі синхронізації. Також додали алерти на «час з останньої синхронізації» і «поточний абсолютний офсет», а не лише «демон запущений».

Урок оптимізації: плавний час — добре, але коректність важливіша. Step при завантаженні — не моральний провал; це контрольована корекція. Робіть її явною і обмеженою.

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

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

Одного ранку апстрім-провайдер мав проблеми, що спричинили сплески jitter. Багато середовищ тихо деградували б. У цьому ж середовищі вибір джерела chrony і межі помилки допомогли, але справжнім героєм була нудна практика: вони регулярно порівнювали вихід chronyc tracking на вибірці вузлів і надсилали алерти для аутлаєрів у частоті та skew, не лише по офсету.

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

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

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

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

  • Симптом: Chrony показує «System clock synchronized: yes», але логи додатка показують відкат часу назад.
    Корінь: Стрибки годинника під час роботи (chrony makestep надмірно дозволений, або інший агент робить step).
    Виправлення: Обмежити step до раннього завантаження (makestep 1.0 3), вимкнути конкуруючі служби часу, дослідити інструменти VM для синхронізації часу.
  • Симптом: Час неправильний відразу після перезавантаження, потім повільно вирівнюється.
    Корінь: RTC неправильний або обробляється як localtime, коли повинен бути UTC.
    Виправлення: Встановити RTC в UTC (timedatectl set-local-rtc 0), потім після синхронізації chrony записати системний час у RTC (hwclock --systohc --utc).
  • Симптом: Офсет продовжує зростати незважаючи на «хороші» джерела.
    Корінь: Нестабільний clocksource або планування віртуалізації, що спричиняє нестабільність частоти; chrony постійно коригує, але втрачає позиції.
    Виправлення: Перевірити clocksource, оновити прошивку, розглянути інший clocksource і вирішити проблему з навантаженням хоста.
  • Симптом: Chrony часто змінює найкраще джерело, з символом ~ «занадто змінний».
    Корінь: Погана якість апстріму NTP, асиметричний мережевий шлях або проблеми фаєрвол/НАТ.
    Виправлення: Використовуйте менше, але якісніші джерела; надавайте перевагу внутрішньому NTP; забезпечте стабільність UDP 123; уникайте hairpin NAT для часу.
  • Симптом: Дрейф відбувається головним чином після suspend/resume.
    Корінь: Поведінка прошивки/clocksource під час сну; розриви часу при відновленні.
    Виправлення: Негайна повторна синхронізація після resume (перезапустіть chrony або форсуйте burst), або вимкнення глибокого сну для систем з суворими вимогами до часу.
  • Симптом: Kerberos «clock skew too great» періодично на деяких вузлах.
    Корінь: Вузли повільно сходяться після простоїв через політику лише slew або отруєння RTC при завантаженні.
    Виправлення: Дозволити контрольовані step на ранньому етапі, заборонити допуск в сервіс до chronyc waitsync, виправити дисципліну RTC.
  • Симптом: Після зміни часової зони/налаштувань DST мітки часу зміщені рівно на годину.
    Корінь: RTC встановлено в localtime у поєднанні з переходами DST, або конфлікти подвійного завантаження.
    Виправлення: Стандартизувати RTC на UTC на Linux-хостах; якщо подвійне завантаження необхідне — виберіть одну політику і впровадьте її послідовно.

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

Чекліст A: Зупинити кровотечу (15–30 хвилин)

  1. Підтвердіть, що chrony запущено: systemctl status chrony.
  2. Вимкніть конкуруючі демони синхронізації часу: видаліть systemd-timesyncd, якщо chrony — головний.
  3. Перевірте нещодавні step-події: journalctl -u chrony | egrep -i 'stepped|wrong by'.
  4. Проаналізуйте tracking і sources: chronyc tracking та chronyc sources -v.
  5. Якщо офсет великий і ви недавно завантажилися — дозволіть контрольований step (налаштуйте makestep) і перезапустіть chrony у вікні обслуговування.

Чекліст B: Зробіть поведінку RTC детермінованою (1–2 години)

  1. Визначте політику RTC: UTC для серверів, якщо немає вагомої причини інакше.
  2. Встановіть політику: timedatectl set-local-rtc 0 --adjust-system-clock.
  3. Почекайте синхронізації: chronyc waitsync 30.
  4. Запишіть коректний системний час у RTC один раз: hwclock --systohc --utc.
  5. Увімкніть rtcsync у chrony, щоб «тримати RTC близько».

Чекліст C: Перевірте стабільність у часі (наступні 24–72 години)

  1. Зафіксуйте базовий стан: chronyc tracking (frequency/skew) і різницю RTC (hwclock --show проти date -u).
  2. Стежте за подіями step у логах.
  3. Якщо частота екстремальна або нестабільна — досліджуйте clocksource і віртуалізацію.
  4. Налаштуйте алерти на «час з останньої синхронізації» і «абсолютний офсет», а не лише «chrony запущено».

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

1) Chrony каже, що синхронізовано. Чому моніторинг усе ще показує дрейф?

Моніторинг може порівнювати з іншим референтом (ще один NTP-сервер, апарат моніторингу або прикладний рівень). Перевірте chronyc tracking і впевніться, що інші служби не змінюють час. Також перевірте стрибки часу в journalctl.

2) Тримати апаратний годинник у UTC чи localtime?

UTC для серверів. Localtime головно для зручності подвійного завантаження з Windows. UTC уникне проблем DST і зменшить випадки «рівно на годину невірно».

3) Чи безпечно дозволяти step часу?

Так, якщо обмежувати його. Дозвольте step рано після завантаження (або після довгих періодів без синхронізації) за допомогою makestep. Уникайте step у робочому стані для систем, чутливих до відкатів часу назад.

4) Що означає «Frequency 18 ppm slow» у chronyc tracking?

Ваш годинник біжить повільніше на 18 частин на мільйон. Це приблизно 1.6 секунди за добу без корекції. Chrony компенсує, регулюючи швидкість системного годинника.

5) Мій RTC відрізняється від системного часу на хвилину. Це нормально?

Ні. Кілька секунд за дні можуть траплятися на слабких RTC. Хвилина вказує на прошивкові/апаратні проблеми, неправильну конфігурацію (localtime/UTC) або що RTC не підтримується (немає rtcsync і немає політики періодичної синхронізації).

6) Чи потрібно регулярно виконувати hwclock --systohc?

Зазвичай ні. Використовуйте rtcsync і дозвольте системі тримати RTC близько. Зробіть одноразовий запис після виправлення конфігурації і додавайте планові записи лише за потреби після вимірювання.

7) Чи може віртуалізація спричиняти дрейф навіть з ідеальними NTP-джерелами?

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

8) Який найшвидший спосіб довести, що RTC — проблема?

Порівняйте RTC із системним часом безпосередньо перед перезавантаженням, перезавантажте систему, а потім порівняйте одразу після старту, ще до збіжності chrony. Якщо пост-boot час починається неправильно в тому ж напрямку — RTC отруює системний годинник при старті.

9) Чому дрейф погіршується під високим навантаженням CPU?

Під тяжким навантаженням гості VM можуть бути дескедульовані і «відстати», а потім наздогнати. На «голому» металі навантаження може виявити проблеми clocksource або поведінку прошивки енергозбереження. Симптом зазвичай — підвищений джиттер і нестабільні оцінки частоти.

10) Чи варто замінити chrony іншим NTP-клієнтом?

Не як перший крок. Chrony загалом відмінний на Debian, особливо для переривчастих з’єднань і сучасних мереж. Більшість «помилок chrony» — насправді неправильне поводження з RTC, конфлікти або проблеми якості апстріму.

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

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

  1. Виберіть один авторитет часу на хості (chrony) і приберіть конкурентів (timesyncd, агентські інструменти, що роблять step).
  2. Зробіть політику step явною: step рано, потім slew. Використовуйте makestep свідомо.
  3. Виправте контракт з RTC: встановіть RTC в UTC, одноразово запишіть правильний час після синхронізації і використовуйте rtcsync, щоб тримати його близько.
  4. Перевірте platform clocksource, якщо частота/skew виглядають нестабільними, особливо у віртуальних машинах.
  5. Операціоналізуйте процес: блокуйте готовність сервісів на основі синхронізації, і налаштуйте алерти на офсет і втрату синхронізації — не лише «демон запущений».

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

← Попередня
Intel XeSS: як Intel приєднався до боротьби через програмне забезпечення
Наступна →
Великі системи, малі помилки: чому «один рядок» може дорого обійтися

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