Часы внутри любого компьютера это не прибор с идеальной точностью, а счётчик колебаний вполне земного кварцевого резонатора, который греется, стареет и плывёт. В этой статье разобрано, почему системное время убегает, как протокол NTP возвращает его к общему эталону, чем опасны резкие скачки часов и что происходит с точностью внутри виртуальных машин. Изложение ведётся с позиции практической метрологии: сначала физика генератора, затем протокол, потом прикладные последствия для служб и администратора.

Кварцевый генератор 32.768 кГц и ошибка в 20 ppm

Часы реального времени, RTC, расположены на материнской плате и питаются от батарейки CMOS, чтобы отсчёт не прерывался даже при выключенном блоке питания. Сердце этого узла кварцевый резонатор на 32.768 Гц. Число выбрано не случайно: это ровно 2 в степени 15, поэтому пятнадцатикратное деление частоты пополам простым двоичным счётчиком даёт ровно один герц, то есть один тик в секунду. Схемотехника получается минимальной и дешёвой, а энергопотребление настолько малым, что литиевого элемента CR2032 хватает на годы.

Проблема в точности. Типовой допуск такого резонатора составляет плюс-минус 20 ppm, то есть двадцать миллионных долей. Пересчёт простой: в сутках 86400 секунд, умножение на 20 миллионных даёт примерно 1.73 секунды возможного ухода за день. За месяц набегает до минуты, за год до десяти минут, и всё это без единого сбоя, просто потому что кварц заведомо отрезан с таким допуском. Ошибка почти всегда систематическая: конкретный экземпляр кристалла стабильно спешит или стабильно отстаёт, что как раз и позволяет программно компенсировать дрейф подстроечным коэффициентом.

Добавляют неопределённости температура и старение. Частота кварца зависит от температуры по параболическому закону с вершиной около 25 градусов: и нагрев от соседнего процессора, и холод плохо проветриваемого корпуса сдвигают частоту вниз от номинала. В серверной с кондиционером дрейф меньше, в системном блоке под столом рядом с батареей больше. Старение кристалла даёт ещё несколько ppm в год, а севшая батарейка CMOS приводит к более грубому эффекту: RTC сбрасывается при отключении питания, и машина просыпается с датой, зафиксированной на момент сборки прошивки. Такие скачки на годы ломают проверку сертификатов ещё до загрузки сетевого стека.

Когда операционная система загружена, она обычно не читает RTC на каждый тик, а заводит собственный программный счётчик на базе таймера прерываний и лишь изредка сверяется с аппаратными часами. Это значит, что у компьютера фактически двое часов, и время при завершении работы часто записывается обратно в RTC, перенося накопленную ошибку с собой.

Протокол NTP и четыре метки времени

Network Time Protocol решает задачу, которая выглядит неразрешимой: как выставить часы по удалённому серверу, если сам сетевой пакет едет неизвестное время. Ответ лежит в измерении круговой задержки. Клиент отправляет запрос по UDP на порт 123 и фиксирует момент отправки по своим часам, это метка t1. Сервер фиксирует момент приёма по своим часам t2, обрабатывает запрос и в момент отправки ответа ставит t3. Клиент, получив ответ, записывает момент приёма t4. В ответе сервера уже лежат t1, t2 и t3, поэтому клиент владеет всеми четырьмя отметками.

Дальше арифметика. Смещение часов клиента относительно сервера вычисляется как ((t2 - t1) + (t3 - t4)) / 2, а полная задержка кругового пути как (t4 - t1) - (t3 - t2). Формула опирается на одно допущение: путь туда и путь обратно занимают одинаковое время. Асимметрия маршрутов вносит остаточную ошибку, из-за которой через обычную сеть честнее говорить о точности в единицы миллисекунд, хотя в локальном сегменте достижимы и сотни микросекунд. Сам пакет компактен, поле времени хранится в 64-битном формате: 32 бита на целые секунды от эпохи 1900 года и 32 бита на дробную часть, что даёт разрешение около 232 пикосекунд.

Иерархия stratum и интервалы опроса

NTP-organизуется как каскад уровней, называемых stratum. Stratum 0 это сами эталоны: атомные часы, цезиевые и рубидиевые стандарты, приёмники спутниковых систем навигации, радиосигналы точного времени. Эти устройства не говорят по сети напрямую. Stratum 1 это серверы, напрямую подключённые к эталону через специальный интерфейс, их ошибка относительно шкалы измеряется микросекундами. Сервер, синхронизирующийся у stratum 1, становится stratum 2, и так далее вплоть до 15 уровня; значение 16 означает, что источник недостижим и синхронизации нет. Клиент обычно держит список из нескольких серверов, сравнивает их показания и отбраковывает явного лжеца, чьё время разошлось с большинством.

Интервал опроса не постоянен. При старте служба опрашивает сервер часто, типовое начальное значение 64 секунды, чтобы быстро собрать статистику и грубо выровнять фазу. По мере того как измерения стабилизируются и оценка дрейфа локального кварца уточняется, алгоритм экспоненциально увеличивает паузу, обычно до 1024 секунд. Такая схема экономит сеть и нагрузку на публичные серверы, не теряя точности: чем лучше известна собственная скорость ухода часов, тем реже нужна внешняя подсказка. Если измерения начинают расходиться, интервал снова укорачивается.

Служба Windows Time и контроль точности

В Windows синхронизацией занимается служба W32Time. У рядовой машины она настроена на иерархию домена, а контроллер домена с ролью эмулятора PDC смотрит наружу; на изолированных станциях часто задан пул серверов Майкрософт. Служба помнит измеренное смещение и способна подтягивать часы даже между сеансами связи, применяя накопленный коэффициент дрейфа.

Диагностика ведётся штатными командами. Оператор выполняет w32tm /query /status и видит источник времени, stratum, момент последней успешной синхронизации, интервал опроса. Команда w32tm /monitor показывает смещение относительно доступных серверов, а w32tm /stripchart /computer:имя строит серию замеров со смещением и задержкой по каждой попытке, что удобно для наблюдения за стабильностью канала. Дополнительно полезны w32tm /resync для принудительного опроса и журнал событий, где служба честно фиксирует пропущенные синхронизации.

Типовая последовательность проверки стенда выглядит так.

  1. Выполнить w32tm /query /status и убедиться, что источник не Local CMOS Clock, а внешний сервер.
  2. Сравнить смещение по w32tm /monitor с допустимым порогом для прикладных служб.
  3. Запустить stripchart на несколько минут и оценить разброс задержки.
  4. Проверить журнал событий Time-Service на период между последними успешными опросами.

Подкрутка против скачка и почему назад ходить нельзя

Когда обнаружено расхождение, есть два способа его устранить. Slewing это плавная подкрутка: система чуть ускоряет или замедляет ход программных часов, например до 0.5 миллисекунды на каждую секунду, и расхождение тает за минуты или часы, не нарушая монотонности. Stepping это мгновенная установка нужного значения. Стандартное поведение дисциплинирующих алгоритмов таково: малые отклонения до сотни-двухсот миллисекунд компенсируются плавно, а большие требуют скачка, потому что подкручивать сутки скоростью в полмиллисекунды бессмысленно. W32Time добавляет собственные пороги MaxAllowedPhaseOffset, регулирующие, что считать малым.

Скачок вперёд неприятен, скачок назад разрушителен. Файловые логи сортируются по меткам времени, и ушедшие в прошлое часы делают хронологию аудита нечитаемой: событие сбоя оказывается записано раньше события запуска. Планировщики пропускают или повторно исполняют задачи. Kerberos по умолчанию допускает расхождение всего плюс-минус 5 минут, и превышение рвёт аутентификацию билетов по всему домену. У TLS-сертификатов жёсткие поля notBefore и notAfter: часы в прошлом объявляют валидный сертификат ещё недействительным, часы в будущем преждевременно просроченным. Распределённые базы данных, полагающиеся на временные метки транзакций, при обратном ходе могут потерять или переупорядочить записи. Именно поэтому операционные системы предоставляют монотонные часы для измерения интервалов, а настенное время используют только как общую шкалу согласования между машинами.

Отдельная боль високосная секунда. Шкала UTC иногда дополняется лишней секундой для согласования с вращением Земли, и сутки получают минуту из 61 секунды. Форматы времени, предполагающие ровно 86400 секунд в сутках, ломаются: Unix time либо повторяет одну и ту же секунду дважды, либо размазывает вставку методом smear на целые сутки, искажая все измерения интервалов в этот период. Практика показала столько инцидентов в крупных системах, что отраслевые органы приняли решение прекратить вставку високосных секунд к 2035 году.

Unix time, часовые пояса и виртуальные машины

Универсальное решение проблемы поясов состоит в разделении шкал. Внутри системы время хранится как Unix time: число секунд, прошедших с полуночи 1 января 1970 года по UTC, без учёта високосных вставок. Это скаляр, одинаковый в любой точке планеты в одно и то же мгновение. Часовые пояса, переходы на летнее время и региональные правила применяются только на этапе отображения для человека через базу IANA tzdata; ядро и сетевые протоколы оперируют исключительно UTC. RTC на Windows исторически держал локальное время, на Linux по традиции UTC, что при двойной загрузке стабильно давало сдвиг на величину пояса, пока обе системы не договаривались об общем соглашении.

Виртуализация добавляет свой слой сложности. Гость видит не физический счётчик TSC процессора, а виртуальный, и пока vCPU простаивает в очереди планировщика гипервизора, виртуальное время отстаёт от настенного. Паравиртуальные интерфейсы вроде vtsc синхронизируют гостевой счётчик с хостом и сглаживают эти провалы; без них дрейф гостя измеряется уже не секундами, а минутами в час под нагрузкой. Гипервизоры при старте выставляют гостевой RTC по часам хоста, а встроенные службы интеграции периодически подтягивают гостя к хосту. Правило практика простое: точность строится цепочкой, хост синхронизируется по NTP с эталоном, гости получают время от хоста или опрашивают NTP сами, но не оба механизма одновременно, иначе два корректора начинают тянуть часы в разные стороны и дрейф вместо затухания начинает колебаться.

Типовые неисправности и практика измерений

Опыт стендовых измерений показывает, что дрейф не обязан быть зловещим: у одного и того же системного блока он почти постоянен, и график смещения в stripchart выглядит как пологая прямая. Тревожные картины другие. Пилообразный график означает, что два независимых корректора по очереди дергают часы, классический случай оставленной службы интеграции гипервизора при собственном NTP-клиенте гостя. Ступеньки через равные промежутки говорят о stepping вместо плавной подкрутки, что бывает при слишком низком пороге MaxAllowedPhaseOffset. Случайный разброс смещения при стабильной задержке указывает на загруженный процессор, где обработка таймерных прерываний опаздывает, а растущая задержка при ровном смещении намекает на перегруженный маршрут до сервера.

Отдельно стоит помнить про эпоху протокола: 64-битное поле NTP переполняется в 2036 году, и хотя современные реализации определяют эпоху по окну вокруг текущей даты, устройство с севшей батарейкой и датой из 2012 года после переполнения утратит способность правильно трактовать ответы. Это ещё один аргумент следить за состоянием CMOS не только ради настроек микропрограммы, но и ради корректной работы сетевой синхронизации. В контролируемом парке полезно задать собственный stratum 2 сервер на базе стабильной машины с хорошим охлаждением, опрашивать с него все остальные и хранить историю измерений: тренд дрейфа конкретного экземпляра оборудования позволяет заметить деградацию кварца задолго до того, как расхождение выйдет за допуски Kerberos и уложит аутентификацию.

Грамотная метрология времени в парке машин сводится к трём опорам: знать физический предел своего кварца, мерить смещение инструментами вместо взгляда на панель задач и никогда не допускать обратного хода часов там, где живут билеты Kerberos, сертификаты и журналы аудита. Часы это такой же измерительный прибор, как осциллограф: без калибровки он показывает числа, а не время.