Почему часы виртуальной машины убегают и кто их незаметно подкручивает
Открываете date на свежем VPS и видите время, которое отличается от реального на секунды, а иногда и на минуты. Это не баг конкретного хостера и не испорченный образ — это устройство виртуализации как таковое. У виртуальной машины физически нет постоянного доступа к аппаратным часам хоста, и то, что гостевая ОС считает «временем», — это реконструкция, которая может съезжать. Разберём, откуда берётся это расхождение, почему оно неизбежно на любом гипервизоре и как его держать под контролем.
Содержание
- Почему у виртуальной машины нет своих часов
- Как гостевая ОС вообще узнаёт время
- Роль планировщика: почему конкуренция за CPU двигает время
- Паравиртуализированные источники времени: как гипервизор помогает гостю не ошибаться
- NTP и chrony: коррекция поверх плывущих часов
- Где рассинхронизация времени реально ломает систему
- Как проверить и настроить синхронизацию на своей VPS
Почему у виртуальной машины нет своих часов
На физическом сервере операционная система напрямую опрашивает аппаратные источники времени: TSC (Time Stamp Counter — счётчик тактов процессора), HPET, PIT или RTC. Это регистры процессора и чипсета, к которым ОС обращается инструкциями rdtsc, in/out и похожими — быстрыми и без посредников.
В виртуальной машине эти же инструкции гостевая ОС тоже выполняет, но напрямую до железа они не доходят. Часть из них (например, обращение к PIT или RTC через порты ввода-вывода) — привилегированные операции, которые процессор не разрешает выполнить непривилегированному гостю: происходит выход в гипервизор (VM exit), гипервизор перехватывает вызов, эмулирует нужное поведение и возвращает управление обратно в гостевую систему. Это не баг, а сознательная часть архитектуры аппаратной виртуализации — так гипервизор контролирует доступ ко всем ресурсам, включая время, а не только к диску и сети.
Проблема в том, что каждый такой перехват стоит времени — микросекунды на переключение контекста между гостем и гипервизором. Сам факт, что гипервизор в этот момент выполняет что-то за гостя, означает, что «сейчас» с точки зрения виртуальной машины и «сейчас» на хосте — это два разных момента, разделённых работой планировщика гипервизора. Современные процессоры позволяют гостю читать счётчик тактов напрямую без перехвата (см. ниже про TSC passthrough), но и это не убирает проблему полностью.
Как гостевая ОС вообще узнаёт время
У гостевой ОС есть несколько источников, из которых она собирает «который час», и это иерархия компромиссов:
- TSC (Time Stamp Counter) — счётчик тактов процессора, инкрементируется на каждом такте (в современных CPU — с постоянной частотой, invariant TSC). Самый быстрый источник, но на многопроцессорных системах и особенно в виртуализации TSC разных виртуальных ядер может рассинхронизироваться между собой, если гипервизор не следит за этим специально.
- HPET / PIT — более старые и медленные таймеры, каждое обращение к ним — это выход в гипервизор с полной эмуляцией. Работают надёжно, но дорого по производительности при частых опросах.
- RTC (Real Time Clock) — батарейные часы материнской платы, используются в основном при загрузке для установки начального времени, дальше ОС переходит на более точные источники.
Ключевой момент: даже если TSC у гостя технически «читается напрямую» (аппаратные расширения это допускают), сама частота, с которой гостевая ОС может пересчитывать этот счётчик в календарное время и синхронизировать его между виртуальными ядрами, зависит от того, насколько регулярно гипервизор вообще предоставляет процессорное время этой конкретной ВМ. Именно здесь начинается настоящая причина расхождения часов.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверРоль планировщика: почему конкуренция за CPU двигает время
Гипервизор одновременно обслуживает множество виртуальных машин на одном физическом узле, и у каждой из них — свои виртуальные ядра, которые по очереди получают реальные такты физического CPU. Пока конкретная ВМ не выполняется (её виртуальные vCPU не запланированы физическим планировщиком), внутренние таймерные прерывания, которые гостевая ОС ожидает получать через равные интервалы (например, тики таймера для планировщика процессов внутри гостя), могут задерживаться или вовсе пропускаться.
Гостевая ОС не знает, что её «поставили на паузу» — с её точки зрения между двумя последовательными тактами просто прошло больше реального времени, чем она рассчитывала. Если гипервизор не компенсирует пропущенные тики отдельным механизмом (а исторически многие так и делали — просто теряли их), внутренние часы гостя начинают отставать от реального времени пропорционально тому, сколько CPU-времени у неё «отняла» конкуренция с соседними ВМ.
Это не единичное событие, а систематический процесс: при высокой загрузке физического узла суммарное время, в течение которого гипервизор физически не может уделить внимание конкретной виртуальной машине, накапливается. Похожая механика стоит за метрикой steal time — она измеряет, сколько CPU-времени ВМ «хотела» получить, но не получила из-за соседей на том же гипервизоре; расхождение часов — один из побочных эффектов той же причины. Подробнее — в статье про steal time и как понять, что сосед ест ваш CPU.
Это не значит, что «плохой» хостинг обязательно даёт более сильный дрейф, чем «хороший» — дрейф заложен в саму модель виртуализации с разделением ресурсов, и абсолютно точное совпадение часов ВМ с реальным временем без коррекции — скорее счастливое совпадение, чем гарантия.
Паравиртуализированные источники времени: как гипервизор помогает гостю не ошибаться
Разработчики гипервизоров решают проблему не только компенсацией задержек постфактум, но и специальными паравиртуализированными интерфейсами — драйверами, которые гостевая ОС устанавливает именно потому, что «знает»: она выполняется в виртуальной среде, и обычные аппаратные предположения о времени здесь не работают в чистом виде.
Несколько примеров таких механизмов:
- kvm-clock — паравиртуализированный источник времени для гостей под KVM/QEMU. Гипервизор экспортирует гостю структуру данных с информацией о том, как пересчитывать TSC в реальное время с учётом пауз в исполнении, и сам обновляет эту структуру при каждом планировании ВМ. Гость читает эти данные без выхода в гипервизор на каждый тик — это быстрее HPET и точнее «наивного» TSC.
- TSC deadline timer и invariant TSC с passthrough — на современном железе гипервизор может разрешить гостю читать TSC напрямую (без перехвата), но при этом гипервизор синхронизирует значения TSC между физическими ядрами и корректно масштабирует счётчик при миграции ВМ между узлами с разной частотой процессора.
- Hyper-V TSC page / VMware Tools time sync — аналогичные механизмы в других гипервизорах: специальная страница памяти или служебный процесс, через который хост передаёт гостю поправки, не дожидаясь, пока рассинхронизация станет заметной.
Общий принцип у всех этих решений один: гость перестаёт делать вид, что работает на голом железе, и использует источник времени, который «знает» об особенностях виртуализации и компенсирует их на лету. Это заметно снижает дрейф по сравнению с эмуляцией классического PIT, но не убирает его полностью — таймер компенсирует известные паузы, а не гарантирует идеальное совпадение с атомными часами. Поэтому даже с хорошим паравиртуализированным клоком коррекция сверху всё равно нужна.
NTP и chrony: коррекция поверх плывущих часов
Здесь в игру вступает NTP (Network Time Protocol) — не как замена аппаратному или паравиртуализированному источнику времени, а как внешний арбитр, который периодически сверяет часы гостя с независимыми серверами точного времени и плавно подстраивает их.
На современных Linux-дистрибутивах для этого чаще всего используется chrony — он лучше ntpd справляется именно со сценарием виртуальных машин, потому что умеет быстрее реагировать на скачки (например, после живой миграции ВМ между хостами) и корректно работает даже при нестабильном сетевом подключении к серверам времени.
Базовая проверка, что синхронизация вообще работает:
timedatectl status
В выводе важны строки System clock synchronized: yes и NTP service: active. Если синхронизация не активна — это стоит исправить в первую очередь, ещё до того, как расхождение станет заметным в логах.
Более детальная картина — через сам chrony:
chronyc tracking
chronyc sources -v
chronyc tracking покажет текущее смещение (System time) и оценку стабильности хода часов (Frequency, Skew) — конкретные значения у каждой машины будут свои и зависят от загрузки узла, сети и выбранных серверов времени, поэтому ориентироваться нужно на собственные наблюдения, а не на чужие цифры из статьи.
Минимальный рабочий chrony.conf для VPS:
# используем пул серверов времени
pool pool.ntp.org iburst
# разрешаем шаг часов при большом расхождении только при старте
makestep 1.0 3
# синхронизируем аппаратные часы (RTC) при выключении
rtcsync
Директива makestep принципиальна для виртуальных машин: если расхождение накопилось (например, после долгой миграции или паузы ВМ), chrony может либо плавно подтягивать время, либо сразу «переставить» часы скачком. Плавная подстройка безопаснее для приложений, чувствительных к движению времени назад, но при большом расхождении разумно разрешить один резкий шаг при старте службы (как в примере выше) и дальше работать плавной коррекцией.
Подробный разбор настройки NTP и chrony на сервере, включая выбор серверов времени и типичные ошибки конфигурации, — в статье про настройку NTP и синхронизацию времени сервера.
Где рассинхронизация времени реально ломает систему
Расхождение в пределах долей секунды почти никогда не заметно и не критично. Проблемы начинаются, когда дрейф накапливается без коррекции или коррекция происходит резким скачком в неудачный момент:
- TLS и подписанные токены. Сертификаты и токены (JWT, OAuth) имеют срок действия, привязанный к абсолютному времени. Если часы сервера отстают или спешат на минуты, валидные токены могут отклоняться как «ещё не наступившие» или «уже истёкшие», а проверка цепочки сертификатов — падать с ошибкой валидности.
- Распределённые базы данных и очереди. Системы, которые используют временные метки для упорядочивания событий или разрешения конфликтов между узлами, могут принимать неверные решения о порядке событий, если часы узлов разошлись — именно поэтому многие СУБД в критичных местах полагаются не только на системное время, но и на внутренние механизмы версионирования строк.
- Логи и мониторинг. Если время на нескольких серверах разное, сопоставление событий по логам между узлами превращается в гадание — инцидент выглядит так, будто событие на бэкенде произошло раньше запроса, который его вызвал.
- cron и запланированные задачи. Резкий скачок времени назад может привести к повторному запуску задачи, которая, с точки зрения cron, «ещё не выполнялась» в текущем окне.
- Авторизация и одноразовые коды. TOTP-коды (Google Authenticator и аналоги) считаются от текущего времени с окном в 30–60 секунд — при заметном расхождении часов легитимные коды начинают не проходить проверку.
Ни один из этих сценариев не требует экзотических условий — все реалистичны на обычном VPS без настроенной синхронизации, особенно после миграции ВМ между узлами или паузы под нагрузкой.
Как проверить и настроить синхронизацию на своей VPS
Практический чек-лист для любого нового или уже работающего сервера:
- Проверьте, что служба синхронизации вообще установлена и активна:
systemctl status chronyd
# или
systemctl status systemd-timesyncd
- Если используется
systemd-timesyncd(упрощённый клиент без коррекции частоты), для продакшена, где важна стабильность хода часов, лучше перейти наchrony— он точнее компенсирует дрейф аппаратного таймера конкретной ВМ:
apt install chrony
systemctl disable --now systemd-timesyncd
systemctl enable --now chronyd
- Убедитесь, что часовой пояс системы соответствует ожиданиям приложений (расхождение часовых поясов путают с рассинхронизацией времени, хотя это разные проблемы):
timedatectl set-timezone Europe/London
- Периодически (не разово при настройке, а на регулярной основе — например, в еженедельном мониторинге) проверяйте
chronyc trackingна предмет растущегоSystem time offset— стабильно растущее смещение между проверками говорит о том, что источники времени недоступны или конфигурация не подхватывается.
- Для приложений, которые критичны к точности времени (платёжные шлюзы, распределённые очереди, системы с TOTP), закладывайте допуск по времени в самой логике — не полагайтесь на то, что часы сервера всегда идеально точны, даже при настроенном NTP: сеть до серверов времени и коррекция всё равно работают с задержкой, а не мгновенно.
Отдельно стоит сказать о выделенных серверах и виртуальных машинах без соседей по гипервизору (например, там, где ресурсы не делятся с другими арендаторами): дрейф часов там тоже возможен из-за самой природы виртуализации, но выражен слабее, потому что нет конкуренции за такты CPU с посторонними нагрузками. Если для вашей задачи точность времени критична, а бюджет позволяет, стоит рассмотреть тариф с гарантированными, а не разделяемыми ресурсами.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверНужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.
Частые вопросы
Если я вижу расхождение в пару секунд на VPS — это повод для тревоги?
Нет, это в пределах нормального поведения виртуализированной системы без специальной настройки. Важнее не разовое значение, а то, растёт ли оно со временем при включённой синхронизации — если да, стоит разобраться, почему NTP-клиент не справляется.
Помогает ли переход с systemd-timesyncd на chrony сам по себе, без дополнительной настройки?
Обычно да, chrony точнее компенсирует нестабильный ход часов и быстрее адаптируется после пауз в работе ВМ, но эффект зависит от конкретной нагрузки и узла — не считайте это гарантированным числом, проверяйте chronyc tracking до и после.
Нужно ли что-то специально настраивать внутри контейнеров (Docker), которые крутятся на VPS?
Обычно нет — контейнеры используют часы хост-системы (ВМ), у них нет отдельного независимого таймера, поэтому синхронизации на уровне ВМ достаточно. Отдельная настройка NTP внутри контейнера, как правило, избыточна и может даже конфликтовать со временем хоста.
Живая миграция ВМ между физическими хостами вызывает более сильный скачок времени, чем обычная работа?
Да, потенциально — во время миграции ВМ на короткое время приостанавливается, и после переноса на новый физический узел могут отличаться и частота TSC, и текущая загрузка нового хоста. Именно для таких случаев в конфигурации chrony имеет смысл держать makestep, чтобы клиент мог быстро исправить разовый скачок, а не пытался бы плавно тянуть время минутами.
Может ли рассинхронизация часов быть у гипервизора, а не только у гостя?
Технически физический хост может отставать от реального времени точно так же, как любой другой сервер, если на нём не настроен NTP. Разница в том, что хост не испытывает того же эффекта пропущенных тактов от «соседей», поэтому его собственный дрейф обычно меньше и стабильнее, но настраивать синхронизацию нужно и на нём тоже.
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →