Files
hse-2026/materials/06-failures/seminar/readme.md
T
2026-10-14 20:13:57 +03:00

17 KiB
Raw Blame History

Семинар 6. Обнаружение отказов и group membership

На семинаре разбираем, как детекторы отказов используются в готовых системах: какие сигналы они получают, почему могут ошибаться и что происходит после обнаружения проблемы. Эти заметки дополняют лекцию 6 и запись семинара. Команды для запуска примеров вынесены в README Envoy и Consul.

Наблюдение и реакция

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

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

Envoy: ошибки при обработке запросов

В демо Envoy один из двух бэкендов случайно возвращает HTTP 500. Прокси учитывает ошибки и временно исключает этот бэкенд из балансировки. Это пассивная проверка: наблюдения появляются только при поступлении обычных запросов.

Прямой запрос к исключённому бэкенду по-прежнему может получить ответ. Envoy меняет маршрутизацию, а процесс продолжает работать. Возврат в балансировку по таймеру также не означает, что причина ошибок устранена.

Consul и Serf

В демо Consul можно сопоставить три вида сведений:

Источник Что показывает
consul members Известных данному агенту участников группы и их статусы
Каталог сервисов Зарегистрированные сервисы
Проверки здоровья Результаты проверок экземпляров приложения

При остановке контейнера приложения его HTTP-проверка перестаёт проходить, хотя агент Consul остаётся доступным. При этом регистрация сервиса ещё может сохраняться в каталоге. Поэтому список зарегистрированных экземпляров и список экземпляров с успешными проверками могут различаться.

Есть и ограничение самой проверки. Обработчик /health в этом примере просто возвращает OK. Он позволяет заметить недоступность HTTP-сервера, но если бы приложение работало с базой данных, потеря доступа к ней осталась бы незамеченной.

За членство самих агентов отвечает другой механизм. Consul использует Serf, который опирается на библиотеку memberlist. Её протокол основан на SWIM с расширениями, включая Lifeguard. Подробнее: gossip в Consul, протокол memberlist.

SWIM и его реализация в Serf

В SWIM каждый участник проверяет других и распространяет изменения состава группы. Узел A отправляет выбранному B сообщение ping. Если ответ не пришёл вовремя, A просит нескольких посредников проверить B и передать ответ. Это помогает, когда прямой обмен A и B нарушен, но через других участников связь ещё работает.

После неудачных проверок B сначала подозревают. У него есть время опровергнуть подозрение, прежде чем наблюдатель пометит его как отказавшего. Такое ожидание уменьшает риск ложного срабатывания, но откладывает обнаружение настоящего отказа.

Сведения об изменениях состава группы передаются вместе с проверочными сообщениями — этот приём называется piggybacking. В сообщение добавляют ограниченное число обновлений, а не всю таблицу участников. Номера версий состояния помогают отличать новые сведения от запоздавших. Пока обновления доходят до остальных, представления участников могут различаться.

В Serf к этому добавлены отдельные gossip-сообщения и периодическая полная синхронизация состояния по TCP. Частоту распространения изменений можно настраивать независимо от частоты проверок, а полная синхронизация помогает восстановить согласованность списков после разделения сети. Эти обмены тоже нужно учитывать при оценке трафика.

Для знакомства с агентами есть Quick Start Serf. Команда serf members показывает alive, left, failed: доступность, штатный выход и обнаруженную недоступность. Запись с failed некоторое время сохраняется в списке. Промежуточное подозрение можно увидеть в логах.

Lifeguard: задержки у наблюдателя

Если A перегружен, он может не успевать обрабатывать ответы здорового B. Ожидание опровержения не всегда спасает от ошибки: пришедшее опровержение тоже может задержаться в обработке. Lifeguard учитывает такие ситуации с помощью трёх расширений SWIM.

Механизм Как работает
Local Health Aware Probe По результатам обмена сообщениями узел оценивает признаки собственных проблем. При их накоплении увеличивает период проверок и таймаут ответа; успешные проверки постепенно уменьшают их.
Local Health Aware Suspicion Начальный таймаут подозрения увеличен. Подтверждения того же подозрения от разных участников сокращают его; их поступление также свидетельствует, что наблюдатель успевает получать и обрабатывать сообщения.
Buddy System При отправке ping подозреваемому в сообщение приоритетно добавляется подозрение о нём. Так он раньше узнаёт о необходимости опровержения.

Lifeguard уже используется в Serf/Consul. В статье его оценивают при задержках обработки сообщений: измеряют ложные срабатывания, время обнаружения настоящих отказов и дополнительный трафик. Увеличение ожидания может замедлить обнаружение, поэтому уменьшение числа ошибок нужно рассматривать вместе с задержками.

Consul и балансировщик

Список здоровых экземпляров нужен, чтобы направлять к ним запросы. Балансировщик или клиентская библиотека может получать его из Consul и обновлять набор доступных адресов. Для этого требуется настроить интеграцию между компонентами. В наших стендах её нет: адреса бэкендов Envoy заданы в конфигурации.

Между проверкой и запросом экземпляр может стать недоступен. Поэтому сведения из Consul дополняют таймауты и обработку ошибок на стороне клиента или прокси.

Примеры из документации и кода

Cassandra: пауза самого наблюдателя

В Cassandra сведения о heartbeat распространяются через gossip, а решение UP/DOWN каждый узел принимает локально. Если процесс надолго потерял процессорное время, после возобновления работы он увидит большие интервалы без heartbeat сразу от многих соседей.

В FailureDetector.interpret() перед вычислением подозрения проверяется время с предыдущего вызова. После долгой локальной паузы детектор временно воздерживается от признания соседей недоступными. Документация Cassandra.

Akka: какие интервалы включать в историю

φ-детектор использует историю интервалов между heartbeat. Если узел долго отсутствовал и вернулся, включение этой паузы в историю изменило бы представление детектора о нормальных задержках.

В heartbeat() φ-детектора новый интервал добавляется в историю только в том случае, если к моменту получения heartbeat узел ещё считается доступным. Так длительный перерыв не искажает статистику обычных интервалов.

Статус unreachable может смениться на reachable, когда связь восстановится. Решение об окончательном исключении участника принимает отдельный механизм. Подробнее: φ-детектор, Split Brain Resolver.

Kubernetes: heartbeat через API

Kubelet сообщает о себе обновлениями статуса узла и объекта Lease. Здесь heartbeat имеет форму обновления ресурса в API Kubernetes. Контроллер при новом Lease запоминает локальное время наблюдения.

Если обновления долго не поступают, условию Ready присваивается значение Unknown: у контроллера нет свежих сведений об узле. Например, связь с управляющей частью могла пропасть, хотя приложения на узле продолжают работать.

Этот механизм следит за узлом в целом. Проверки readiness и liveness относятся к контейнерам приложения: они позволяют отдельно оценивать готовность принимать трафик и необходимость перезапуска. Документация heartbeat узлов.

Цена обнаружения и распространения сведений

В дополнение к оценкам на слайдах 21–22 и 29 лекции посчитаем расходы для условной группы из 1000 процессов. Запись занимает 32 байта, служебная часть сообщения — 64 байта, период отправки — одну секунду.

Во всей группе за секунду All-to-all: своя запись каждому Gossip: полная таблица одному соседу
Сообщений 999 000 1000
Объём отправок ≈95,9 МБ ≈32,1 МБ

МБ здесь — миллион байт; транспортные заголовки, фрагментация и повторные передачи не учтены. Сообщений стало почти в тысячу раз меньше, а объём сократился лишь втрое: обе схемы передают порядка миллиона записей. Получатель обрабатывает либо много маленьких сообщений, либо большие таблицы.

Одинаковый период не обеспечивает одинаковую задержку распространения сведений. Расходы сравнивают при сопоставимых требованиях к задержке и ложным подозрениям. Помимо сообщений и байтов, измеряют CPU и нагрузку на отдельных участников. Нужны и замеры при отказах: например, в SWIM отсутствие прямого ответа вызывает дополнительные проверки через посредников.

Дополнительное чтение