Статьи

Распределенное время

Если вы запустите команду date на вашем (Unix) компьютере, вы увидите что-то вроде:

$ date
Mon Nov 25 07:56:59 CET 2013

в вашем часовом поясе выбора. Это время происходит от аппаратной части, локальной для вашей машины, встроенной где-то на материнской плате и обычно работающей от батареи BIOS. Чем больше ваша система, тем сложнее будет определить текущее время.

Часы дрейфуют

Время, считываемое по дате, называется системным временем; оно отделено от фактического времени, считываемого с аппаратных часов во время загрузки, и передается при каждом прерывании таймера, создаваемом специализированной схемой. Это время может даже быть в разных часовых поясах: вы можете установить системное время в часовой пояс вашей страны, сохраняя аппаратные часы в UTC.
hwclock запросит у вас аппаратные часы:

$ hwclock
Wed 06 Nov 2013 02:12:28 PM CET  -0.287960 seconds

Выполнение той же команды с параметрами отладки немного объясняет, как работают часы:

$ hwclock --debug
hwclock from util-linux-ng 2.17.2
Using /dev interface to clock.
Assuming hardware clock is kept in local time.
Waiting for clock tick...
...got clock tick
Time read from Hardware Clock: 2013/11/06 14:13:24
Hw clock time : 2013/11/06 14:13:24 = 1383743604 seconds since 1969
Wed 06 Nov 2013 02:13:24 PM CET  -0.450946 seconds

Я выполнил эту команду на виртуальной машине, которая находилась в спящем режиме в течение нескольких недель, поэтому вы можете видеть, что время застревало на всех интервалах, в течение которых машина сохранялась на диске. Запуск того же на физической машине дает:

$ hwclock --debug
hwclock from util-linux-ng 2.17.2
Using /dev interface to clock.
Assuming hardware clock is kept in local time.
Waiting for clock tick...
...got clock tick
Time read from Hardware Clock: 2013/11/06 14:13:24
Hw clock time : 2013/11/06 14:13:24 = 1383743604 seconds since 1969
Wed 06 Nov 2013 02:13:24 PM CET  -0.450946 seconds

Часы идут через тики, которые происходят с фиксированной частотой, такой как 4000 Гц. Этот тик принимается ядром, которое соответственно увеличивает свое время. Тем не менее, частота прерывания устанавливается только с допуском.

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

Введите NTP

NTP — это протокол, который выполняет автоматическую настройку времени компьютера, поддерживая на нем демон (ntpd на машинах Unix) и опрашивая внешние серверы времени. Серверы времени управляются статистическими институтами (IEN в моей стране), которые подключают машины к точным аппаратным средствам, таким как атомные часы, например, те, которые работают на спутниках GPS.

Полное описание протокола может представлять собой небольшую отдельную книгу, но она работает примерно так:

  • локальная система A знает, что ее часы дрейфуют, и отправляет исходящий пакет на сервер времени B, отмечая его A1.
  • сервер времени B отвечает другим пакетом, отмеченным реальным временем B1.
  • А получает этот пакет в местное время А2.
  • A теперь знает, что реальное время в A1 + (A2-A1) / 2, при условии симметричной задержки, было B1. Он может настроить свои часы, чтобы соответствовать в B1 + (A2-A1) / 2.

(на самом деле маркеры являются более сложными: сервер имеет отметки времени B1 и B2 приема пакета и передачи ответа. Кроме того, процесс повторяется, и его результаты статистически анализируются. NTP также отличается сложностью в виде уровней серверов, но мы не собираемся туда.)

Мы хотим сосредоточиться только на последнем этапе: корректировка. Часы под управлением NTP могут настраиваться, особенно при высокой нагрузке, на секунды или десятки секунд.

Это означает, что в вашей базе данных вы можете регистрировать такие события, как:

  • сообщение (1, in_response_to = NULL, текст = …, созданный_ат = 14: 13: 24)
  • сообщение (2, in_response_to = 1, текст = …, созданный_ат = 14: 13: 22)

что может осложнить вашу жизнь, когда клиент спрашивает, как возможно, что ответ был создан перед вопросом. Они сказали, что программирование — это легкая работа, верно? Этот сценарий может произойти, особенно когда сообщения генерируются не людьми, а автоматизированными процессами.

Несколько серверов

Причина, по которой NTP так широко используется, заключается в том, чтобы синхронизировать парк серверов с одним источником времени. Даже в этом случае система не идеальна, поскольку каждая машина работает в соответствии со своими локальными аппаратными часами.

Даже если все часы медленнее эталонного и показывают задержку относительно источника, описанная выше ситуация все же возможна из-за относительного отличия от машин. Предположим, что реальное время 14:13:25, когда 1 и 2 вставлены последовательно, но на разных серверах:

  • message (1, in_response_to = NULL, text = …, creation_at = 14: 13: 24) // машина с более медленным тактовым сигналом относительно источника
  • message (2, in_response_to = 1, text = …, creation_at = 14: 13: 22) // машина с более медленным тактом по сравнению с другим

Создание времени генерации базы данных решает проблему только до тех пор, пока для записи требуется более одного компьютера, и это компенсирует тестируемость кода, который зависит от времени, которое теперь зависит от базы данных.

Решительным решением является запрос времени у централизованного сервера, который вносит задержку и становится единственной точкой отказа (и все еще подвергается корректировкам). Более прагматичное решение — указать, что все моменты времени, собранные приложением, если они не чувствительны, имеют 10-секундный допуск.

Выводы

Время — сложное понятие: неудивительно, что несколько тысячелетий прошло с зари цивилизации до того момента, когда мы приобрели инструменты, достаточно точные для измерения секунд и миллисекунд (вспомним песочные часы). Небольшие ошибки накапливаются до тех пор, пока точные часы не сместятся друг с другом и не потребуются постоянные обновления; что является проблемой с распределенными системами и необходимость допусков раздела …