АрхитектураРаспределённые системыАрхитектор распределённых систем

Как защитить хранилище от записи старого лидера после восстановления сетевого разделения?

Как защитить хранилище от записи старого лидера после восстановления сетевого разделения?

Проходите собеседования с ИИ помощником Hintsage

Краткий ответ

Используйте fencing token — монотонно возрастающий маркер эпохи лидера. При каждой выдаче лидерства координатор увеличивает токен, а хранилище принимает запись только от владельца токена, который не старше последнего принятого.

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

Исторический контекст

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

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

Постановка проблемы

Пусть узел A получил право быть лидером и начал запись в хранилище. Затем между A и координатором возникло сетевое разделение, координатор назначил лидером узел B, а A из-за задержки или паузы ещё не знает об этом.

Если хранилище принимает команды только на основании локального факта «A когда-то был лидером», старый узел может перезаписать данные, созданные B. Это приводит к потере обновлений, нарушению инвариантов или расхождению состояния после восстановления сети.

Подробное решение

Координатор выдаёт каждому новому владельцу ресурса новый fencing token: например, 41, затем 42. Лидер прикладывает свой токен к каждой операции, а хранилище хранит максимальный уже принятый токен.

Операция с токеном 42 обновляет данные и фиксирует значение 42. Любая последующая операция с токеном 41 отклоняется, даже если она пришла позже и от узла, который формально ещё считает себя лидером. Таким образом, порядок эпох проверяется там, где происходит опасное изменение состояния.

Токен должен быть связан с операцией записи атомарно: нельзя сначала проверить его, а затем независимо выполнить запись, иначе две конкурентные операции могут обойти проверку. Хранилище также должно действительно обеспечивать сравнение токенов; передача токена только между клиентами без принудительной проверки не даёт защиты.

Lease и fencing решают разные задачи. Lease ограничивает период, в течение которого координатор считает узел владельцем, а fencing не позволяет старому владельцу воздействовать на ресурс после утраты права. Надёжная схема обычно использует оба механизма: lease для обнаружения устаревшего лидера и токен для защиты записи.

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

Ситуация из практики

Сервис назначает лидера для обработки одного платежного потока. Лидер A получил lease и токен 17, но затем надолго завис из-за паузы виртуальной машины. Lease истёк, координатор назначил лидером B и выдал ему токен 18.

Вариант с одним lease опасен: после возобновления A может отправить старую команду списания или изменить статус платежа. Вариант с повторной проверкой лидерства перед каждой операцией уменьшает риск, но не закрывает окно между проверкой и записью, а при сетевой проблеме A всё равно может использовать устаревшие данные.

Выбран вариант, при котором платежное хранилище принимает запись только вместе с токеном и атомарно отклоняет токены меньше последнего принятого. B с токеном 18 успешно обрабатывает платеж, а поздняя команда A с токеном 17 отклоняется. Система сохраняет единственного действительного автора изменений без необходимости доверять своевременной остановке старого процесса.

Что кандидаты часто упускают

  1. Достаточно ли просто установить короткий тайм-аут аренды?

Нет. Тайм-аут сообщает координатору, что владелец, вероятно, потерял право, но старый процесс может не получить это сообщение и продолжить работу. Пока ресурс не проверяет fencing token, он не отличает действующего владельца от устаревшего.

  1. Где должна проверяться актуальность fencing token?

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

  1. Что произойдёт, если токены монотонны, но запись и обновление последнего токена не атомарны?

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