Heartbeat
Heartbeat
Heartbeat (сердцебиение) — это регулярный сигнал «я жив», который один
компонент системы отправляет другому через фиксированные промежутки времени.
Пока сигнал приходит вовремя — считается, что источник работает; пропало
несколько сигналов подряд — источник считается сломавшимся, и включаются
заранее оговорённые действия: алерт, перезапуск, переключение на резерв.
История
Сама идея старше компьютеров. В телеметрии первых баллистических ракет и
спутников 1950-х уже был «маяк» (beacon): аппарат непрерывно передавал
короткий радиосигнал, и пока сигнал слышен — считалось, что аппарат жив и
летит. У «Спутника-1» в октябре 1957 года это буквально был знаменитый
писк на частоте 20 МГц — простейший heartbeat планетарного масштаба.
В вычислительной технике параллельно развивалась идея watchdog-таймера
(«сторожевой таймер»): аппаратный счётчик, который сам себя сбрасывает,
если процессор регулярно к нему обращается, и жёстко перезагружает
машину, если обращений долго нет. Первые упоминания — конец 1960-х,
массово — в промышленной электронике и авионике 1970-х.
Дальше — вехи именно термина «heartbeat» в софте:
- 1981 год — стандарт TCP (RFC 793) не имел keepalive «из коробки», но
уже в 1989-м в RFC 1122 официально описали механизм TCP keepalive:
пустые пакеты через долгий интервал, чтобы понять, жив ли собеседник на
другом конце соединения. Это heartbeat на уровне транспортного протокола. - Конец 1990-х — в мире Linux рождается проект под прямым названием
«Heartbeat» (примерно 1999 год, автор Алан Робертсон, часть Linux-HA).
Два сервера гоняли друг другу сигналы по последовательному кабелю или
Ethernet; если основной замолкал, резервный подхватывал IP-адрес и
сервисы. Позже проект эволюционировал в Pacemaker + Corosync. - 2006 год — выходит статья про Chubby от Google, а в 2010 — про
Raft-подобные механизмы становятся мейнстримом (сам Raft опубликован
Диего Онгаро и Джоном Оустерхаутом в 2014-м): в алгоритмах выбора
лидера heartbeat от лидера к последователям — центральный механизм. - 2010-е — heartbeat становится стандартной частью оркестраторов
(Kubernetes, 2014), очередей сообщений (Kafka consumer heartbeat,
~2015), сервисов обнаружения (Consul, etcd). - 2014 год — уязвимость Heartbleed в OpenSSL: ошибка была именно в
реализации heartbeat-расширения TLS. Слово «heartbeat» на пару недель
попало в мировые новости — правда, по неприятному поводу.
Сегодня это один из самых базовых кирпичиков любой распределённой
системы: без него нельзя честно ответить на вопрос «а этот сервер вообще
ещё работает?».
Что это такое
Представь двух людей, которые договорились: «Пока я пишу тебе в чат
короткое „ок“ каждую минуту — со мной всё нормально. Молчу пять минут
подряд — вызывай скорую». Это и есть heartbeat в чистом виде. Один
конец периодически отсылает сигнал, второй следит за расписанием
поступления и реагирует на пропуск.
Разбираем важные пары различий, потому что термины путают постоянно.
Heartbeat vs health check. Heartbeat — сигнал в одну сторону, отправляет
сам «пациент»: «я жив, я жив, я жив» (это называют push-модель). Health check
(«проверка здоровья») — обычно наоборот: наблюдатель сам ходит и спрашивает
«ты жив? покажи внутренности», получает ответ с деталями (это pull-модель).
Часто внутри health check как раз реализована функция, которая проверяет
«не устарел ли последний heartbeat».
Heartbeat vs polling (опрос). Polling — это «наблюдатель сам стучится в
дверь по расписанию». Heartbeat — «жилец сам кричит из окна по расписанию».
При heartbeat инициатива у источника, при polling — у наблюдателя. Разница
принципиальна для случаев, когда наблюдатель не может достучаться до
источника: он за NAT, за файрволом, в мобильной сети без внешнего IP.
Тогда heartbeat — единственный способ.
Heartbeat vs watchdog (сторожевой таймер). Watchdog — почти всегда
локальный: процессор пишет в регистр «я живой», и если долго не пишет —
аппаратура жёстко его перезагружает. Heartbeat — почти всегда сетевой:
между процессами, машинами, датацентрами. Идея одна («молчание = смерть»),
масштаб разный.
Liveness vs readiness. В Kubernetes прижилась чёткая пара:
liveness probe («жив ли контейнер вообще, не завис ли») и readiness probe
(«готов ли принимать трафик прямо сейчас — прогрел ли кэш, подключился ли
к базе»). Первый пропуск заканчивается перезапуском контейнера, второй —
временным выведением из балансировки. Heartbeat как термин обычно
относится к первому.
Важный принцип: сам факт прихода heartbeat не гарантирует, что система
работает правильно. Он гарантирует только, что процесс, отвечающий за
отправку heartbeat, крутится и до сети дотягивается. Если приложение
внутри зависло на бесконечной обработке одного запроса, а фоновый
поток продолжает отправлять «я жив» — снаружи всё выглядит здоровым.
Поэтому в зрелых системах heartbeat совмещают с более честными
проверками: «сходить в базу», «обработать тестовый запрос».
Аналогии из жизни
Ребёнок в игре в прятки, который громко считает. Пока водящий слышит
«раз, два, три...» — он знает: игрок жив, играет по правилам, стоит у
стены и не подглядывает. Замолчал — либо ушёл жульничать, либо ушёл на
кухню за печеньем.
Где ломается: ребёнок может считать вслух, но подглядывать одним глазом
— формально жив, по существу читерит. Ровно так же процесс может слать
heartbeat, но внутри быть намертво зависшим на реальной работе. Сигнал
подтверждает только то, что механизм счёта работает, а не то, что игра
идёт честно.
Кардиомонитор в больничной палате. Пикает при каждом ударе сердца
пациента, а при остановке ритма кричит громким тревожным сигналом.
Медсестра на посту не смотрит непрерывно — она реагирует только на
молчание монитора или на тревогу.
Где ломается: датчик может отвалиться от кожи, и монитор закричит,
когда пациент здоров и хочет спать (ложная тревога). Или наоборот,
провод может касаться и давать красивую линию, когда пациенту плохо.
Ровно те же две беды в IT: ложные срабатывания от сетевого сбоя между
источником и наблюдателем и ложное спокойствие, если heartbeat идёт «в
обход» настоящего состояния системы.
Регулярный звонок бабушке. Договор: «Звоню каждое воскресенье в семь
вечера. Если два воскресенья подряд не позвонил — езжай проверять».
Простая, дешёвая, честная модель heartbeat: интервал, порог пропусков
(два), действие при срабатывании (езжай проверять).
Где ломается: бабушка живёт в деревне, где связь пропадает по погоде.
Пропущенный звонок означает не «беда», а «дождь». В IT то же самое:
надо отличать «источник умер» от «сеть между нами моргнула». Обычно
это лечится порогом («не один пропуск, а три подряд») и учётом
косвенных признаков («а другие соседи бабушки на связи?»).
Как это работает
Разберём типовую схему по шагам.
Шаг 1. Договор. Отправитель (sender) и приёмник (receiver) заранее
договариваются о трёх числах:
- Интервал (period, tick) — как часто слать сигнал. Типичные значения:
1 секунда (кластерные системы, где важно быстрое обнаружение),
10–30 секунд (Kafka consumer heartbeat, Consul), 1 минута (мониторинг
cron-задач), несколько минут (мобильные приложения, чтобы не сажать
батарею). - Таймаут (timeout, session timeout) — сколько ждать до объявления
«источник умер». Всегда заметно больше интервала — минимум в 2–3 раза,
чтобы одна потерянная посылка не приводила к ложной тревоге. - Порог пропусков (threshold, missed count) — сколько сигналов подряд
можно пропустить, прежде чем реагировать. Обычно 2–5.
Шаг 2. Отправка. Отправитель раз в интервал отсылает короткое
сообщение. Формат зависит от контекста: TCP-пакет без данных с флагом
ACK (TCP keepalive), UDP-датаграмма, HTTP POST на URL мониторинга,
запись строки в таблицу базы, вызов RPC-метода.
Псевдокод простого heartbeat в фоновой задаче:
while running:
try:
send_heartbeat(job_id, status="ok", timestamp=now())
except Exception as e:
log(e)
sleep(interval)
Шаг 3. Наблюдение. Приёмник ведёт таблицу «когда в последний раз я
слышал каждого». Отдельный процесс раз в интервал сверяет её с текущим
временем:
for job_id, last_seen in heartbeats.items():
if now() - last_seen > timeout:
raise_alert(job_id)
Шаг 4. Реакция. Что именно происходит при обнаружении молчания —
зависит от роли системы:
- Алерт: отправить сообщение в мессенджер, в почту, дежурному в
PagerDuty. - Failover (переключение): назначить резервный узел новым лидером и
переключить на него трафик. - Перезапуск: kubelet прибивает контейнер и запускает заново.
- Изменение UI: в админке появляется красный баннер «сервис Х молчит».
Шаг 5. Возврат в норму. Когда сигнал возобновляется, наблюдатель
снимает алерт (или пишет отдельное «recovery»-событие), сбрасывает
счётчик пропусков и возвращает узел в строй.
Push vs pull. Push (то, что мы описали) — источник сам шлёт. Pull —
наблюдатель сам ходит и спрашивает. Push дешевле для наблюдателя
(меньше сетевых запросов на всех сразу) и работает через NAT/файрвол,
но требует, чтобы источник знал адрес наблюдателя. Pull даёт
наблюдателю больше контроля (может спросить дополнительно, может
пропустить проверку под нагрузкой) и удобнее для внешних клиентов
мониторинга. В реальности часто гибрид: клиент отправляет heartbeat,
а раз в час наблюдатель делает контрольный pull для сверки.
Ложные срабатывания и jitter. Если тысяча процессов настроена
слать heartbeat ровно в HH:MM:00, один сбой сети создаст лавину
одновременных «пропали». Лечится jitter (дрожанием) — добавлением
небольшого случайного сдвига к интервалу: не ровно 60 секунд, а
55–65. Тот же приём распределяет нагрузку на приёмник ровным ковром
вместо пиков.
Выбор интервала — это компромисс. Слишком часто (1 сек) — нагрузка
на сеть и приёмник, лишний расход батареи для мобильных клиентов,
масса ложных срабатываний. Слишком редко (10 минут) — узнаёшь о падении
через 20–30 минут, за это время клиенты успевают разозлиться.
Правило большого пальца: интервал ≈ 1/10 от допустимого времени
обнаружения сбоя.
Heartbeat лечит слепоту, но не глухоту
Сам по себе сигнал говорит только «процесс жив и до наблюдателя дотягивается». Он не говорит, что приложение работает правильно, что база отвечает, что очередь не переполнена. В зрелой системе heartbeat — самый низкий уровень пирамиды: над ним health check с проверкой зависимостей, а над ним — метрики бизнес-смысла («сколько заявок за минуту прошло»).
Где встречается в обычной жизни
- «В сети» в мессенджерах. Приложение раз в 20–30 секунд отправляет
на сервер короткий пинг; молчание больше нескольких минут — статус
меняется на «был(а) недавно». Именно heartbeat отвечает за зелёный
кружок рядом с аватаркой. - Умные часы и фитнес-трекеры. Часы каждые несколько секунд шлют
телефону короткое «я здесь», а телефон при потере сигнала показывает
«часы отключены». В обратную сторону — приложение шлёт heartbeat на
сервер, поэтому статистика синхронизируется даже когда экран погашен. - Домофон и охранные системы. В нормальном режиме контрольная
панель раз в несколько минут отправляет на пульт короткое «всё в
порядке». Отсутствие сигнала — не то же самое, что тревога, но
оператор перезванивает и проверяет. - Банкоматы и терминалы оплаты. Каждые несколько минут терминал
докладывается процессинговому центру. В диспетчерской карта города
усыпана точками; точка становится красной — техника едет менять
чековую ленту или чинить связь. - Автомобильные системы связи (eCall в ЕС). Автомобиль периодически
общается с сервером производителя. Если после аварии сигнал резко
оборвался, а датчики удара сработали — вызов автоматически уходит
спасателям.
Где встречается в IT и бизнесе
- Обнаружение падений серверов. Нужно, когда важно узнать о смерти
узла за секунды, а не когда позвонит первый пользователь. Kubernetes,
Consul, etcd, Nomad — всё вокруг heartbeat. - Выбор лидера в распределённых системах. Нужно, когда группа узлов
должна согласованно решать, кто главный. В Raft лидер шлёт heartbeat
каждые 50–150 мс; если последователи не слышат его 150–300 мс,
начинаются перевыборы. - Мониторинг cron-задач и фоновых воркеров. Нужно, когда «нет
новостей» — плохие новости: задача должна была отработать в 4 утра,
но не отработала — и никто об этом не узнал бы без heartbeat. Здесь
применяется вариант dead man's switch: «если я не пришлю сигнал
вовремя — кричи тревогу». - Отслеживание сессий пользователей и подключений клиентов. Нужно,
когда сервер должен освобождать ресурсы после отвалившихся клиентов:
Kafka выгоняет consumer из группы, если тот не прислал heartbeat
вовремя; WebSocket-серверы закрывают «тихие» соединения. - Мониторинг целостности сетевых каналов. Нужно, когда критично
быстрое обнаружение обрыва: BGP-роутеры шлют друг другу keepalive
раз в 30 секунд, VPN-туннели — раз в 10.
Кто пользуется
- Kubernetes. Liveness probes и readiness probes у контейнеров;
kubelet шлёт своё «я жив» в API-сервер (node heartbeat) раз в 10
секунд по умолчанию, узел объявляется NotReady примерно через 40
секунд молчания. - ZooKeeper / etcd / Consul. Классические системы координации:
клиент держит сессию за счёт периодических heartbeat, узлы кластера
через heartbeat выбирают лидера и обнаруживают сбои. - Apache Kafka. У консьюмеров есть отдельный поток heartbeat к
координатору группы (heartbeat.interval.msпо умолчанию 3 секунды,
session.timeout.ms— 45 секунд в новых версиях). Пропустил
таймаут — тебя выкинули из группы и раздали твои партиции соседям. - Raft и его реализации (etcd raft, HashiCorp raft, TiKV):
heartbeat от лидера — механизм подавления новых выборов. - Специализированные сервисы cron-мониторинга. Healthchecks.io
(open-source, есть self-hosted), Dead Man's Snitch, Cronitor,
Better Uptime. Идея одна: даёшь URL, cron-задача в конце шлёт туда
GET; не пришёл — прилетает алерт в Slack/Telegram/почту. - Финансовые протоколы. FIX-протокол на биржах требует
heartbeat между сторонами каждые 30 секунд по умолчанию. - TLS/DTLS. То самое расширение Heartbeat из RFC 6520, из-за
ошибочной реализации которого случился Heartbleed в 2014-м.
Расширение живо, реализация исправлена.
Альтернативы и конкуренты
- Pull-based health check.
Плюс: наблюдатель контролирует ритм, легко масштабируется под свою
нагрузку, удобен для внешних систем мониторинга.
Минус: не пробьётся через NAT/файрвол, требует, чтобы наблюдатель
знал адрес каждого источника. - Watchdog-таймер (аппаратный или локальный программный).
Плюс: работает даже когда ОС наполовину мертва; жёсткий и быстрый
ответ (перезагрузка железа).
Минус: только про «сам себя»; ничего не знает про удалённые сервисы,
зависимости, бизнес-логику. - Event-driven мониторинг логов и метрик (алерт по появлению
ошибок, по падению RPS).
Плюс: ловит именно бизнес-проблемы, а не только «жив/мёртв»;
реагирует на деградацию раньше полной смерти.
Минус: если источник умирает молча — логов и метрик просто нет,
и алерт не срабатывает. Без heartbeat есть слепое пятно
«тишины». - Lease / TTL (аренда с истечением срока).
Плюс: элегантная модель, где сам факт удержания ресурса требует
регулярного продления — не продлил, ресурс освобождается автоматически.
Минус: по сути это переупаковка heartbeat с той же математикой
интервалов и таймаутов, только с более жёсткой семантикой; для
простых «жив ли ты» — оверкилл.
Когда НЕ стоит использовать
- Для одноразовых коротких задач (обработка одного HTTP-запроса,
скрипт, отрабатывающий 200 мс) — потому что заводить heartbeat
дороже, чем сама задача; проще один раз в конце сообщить результат. - Как единственный сигнал качества сервиса — потому что heartbeat
подтверждает жизнь процесса, а не корректность работы. Нужно
дополнять метриками бизнес-смысла: сколько заявок обработано,
какой процент ошибок, задержки. - В сетях с высокой стоимостью соединения или сильно ограниченной
батареей без специальной оптимизации — потому что частые сигналы
съедят трафик и заряд быстрее, чем полезная нагрузка. Для мобильных
клиентов приходится растягивать интервал до минут и использовать
push-уведомления вместо своего постоянного соединения.
Тишина — тоже сообщение
Главная сила heartbeat не в том, что мы слышим сигнал, а в том, что мы умеем интерпретировать его отсутствие. Ровно поэтому у heartbeat всегда есть тройка «интервал — таймаут — порог»: без честно заданного порога любая пропущенная посылка превращается либо в ложную тревогу, либо в проигнорированную беду.
Связанные понятия
- Health check — активная проверка состояния сервиса, обычно
pull-моделью и с детальным ответом («база: ок, очередь: ок»). - Watchdog — сторожевой таймер, обычно локальный, обычно
жёстко перезагружающий машину при молчании. - Failover — автоматическое переключение с упавшего узла на
резервный, часто триггерится именно по отсутствию heartbeat. - Split-brain — ситуация, когда сеть разорвана и обе половины
кластера считают себя лидером; классическая ловушка систем на
heartbeat, лечится кворумом. - Dead man's switch (кнопка мертвеца) — механизм «если я не
подтвердил, что жив, — значит, случилось плохое, действуй».
Cron-мониторинг — прямое воплощение. - TTL (time-to-live) / lease — срок жизни записи, после которого
она считается недействительной; та же математика, что и у
heartbeat, но в терминах данных.
Литература и источники
- Wikipedia: https://en.wikipedia.org/wiki/Heartbeat_(computing) —
общий обзор (en). - Wikipedia: https://en.wikipedia.org/wiki/Watchdog_timer — соседняя
тема, полезная для понимания различий (en). - RFC 1122 «Requirements for Internet Hosts — Communication Layers»
(1989) — где официально описан TCP keepalive. - RFC 6520 «TLS/DTLS Heartbeat Extension» (2012) — тот самый
протокол, ставший знаменитым через Heartbleed. - Diego Ongaro, John Ousterhout, «In Search of an Understandable
Consensus Algorithm» (Raft, 2014, en) — раздел про AppendEntries
как heartbeat. - Martin Kleppmann, «Designing Data-Intensive Applications» (2017,
en; русский перевод «Высоконагруженные приложения») — главы про
распределённые системы, обнаружение сбоев, split-brain. - Документация Kubernetes: liveness/readiness probes и node
heartbeat — искать «kubernetes liveness readiness probe» и
«kubernetes node heartbeat» на kubernetes.io. - Документация healthchecks.io — практический пример dead man's
switch для cron-задач.
Где встретилось у меня
Вчера в сервисе мониторинга рекламных кампаний проектировалась
таблица cron_heartbeat в SQLite: каждый фоновый job в конце
работы делает upsert строки со своим статусом и временем; поверх
этого — детектор протухшего OAuth-токена внешней рекламной системы
с алертом в мессенджер и красным баннером в админке. Ровно тот
самый dead man's switch: молчание job'а — сигнал, что что-то пошло
не так, ещё до того, как это увидит менеджер.
Краткое резюме
- Heartbeat — регулярный сигнал «я жив» от источника к наблюдателю;
интерпретируется его отсутствие, а не наличие. - Всегда задаётся тройкой чисел: интервал, таймаут, порог пропусков —
без них не бывает ни надёжного обнаружения, ни защиты от ложных
тревог. - Работает через NAT/файрвол лучше pull-проверок и потому доминирует
в клиент-серверных и распределённых системах. - Подтверждает жизнь процесса, но не корректность работы — поверх
нужны health check с проверкой зависимостей и бизнес-метрики. - Классические ловушки: split-brain при разрыве сети, ложные тревоги
от синхронных пиков (лечится jitter), забытый heartbeat в мёртвом
коде (см. историю Heartbleed).