Разберите, какую проблему решают fencing tokens при истечении распределённой блокировки.
Fencing tokens не дают старому владельцу распределённой блокировки продолжить изменять ресурс после истечения его аренды. При каждом новом захвате блокировки координационный сервис выдаёт монотонно возрастающий токен, а сам ресурс принимает операцию только с токеном не меньше последнего принятого.
Это защищает от ситуации, когда старый клиент из-за паузы, сетевой задержки или сбоя считает себя владельцем, хотя блокировка уже выдана другому клиенту. Одной проверки блокировки в отдельном сервисе недостаточно: ресурс должен сам проверять токен в момент записи.
Распределённые блокировки часто строятся как аренды с ограниченным временем действия. Такой подход позволяет автоматически освободить блокировку, если владелец отказал или потерял связь с координационным сервисом.
Однако истечение аренды не останавливает процесс-владельца физически. Он может надолго зависнуть, например из-за паузы сборщика мусора, а затем продолжить выполнение уже после того, как блокировка была выдана другому клиенту. Поэтому возникла необходимость защищать не только сам механизм выдачи блокировки, но и конечный ресурс.
Пусть клиент A получил блокировку и начал обновлять общий ресурс. Затем его выполнение приостановилось, аренда истекла, а клиент B получил ту же логическую блокировку и начал работать с ресурсом.
Если клиент A возобновится позже, он может отправить отложенную запись после записи клиента B. Координационный сервис уже считает A неактуальным, но ресурс может не знать об этом и принять устаревшую операцию. В результате новые данные будут перезаписаны старыми, а обычная проверка статуса блокировки не устранит гонку между проверкой и записью.
При выдаче блокировки координационный сервис увеличивает счётчик и возвращает клиенту новый fencing token. Например, клиент A получает токен 41, а после истечения его аренды клиент B получает токен 42.
Клиент передаёт токен вместе с операцией к защищаемому ресурсу. Ресурс хранит последний принятый токен и принимает запрос только если новый токен больше либо соответствует правилам, заданным для конкретной операции. Запрос с токеном 41 после успешной операции с токеном 42 отклоняется как устаревший.
Ключевой принцип состоит в том, что проверка должна выполняться там, где производится изменение ресурса, в рамках его собственной модели согласованности. Если токен проверяет только клиент или отдельный сервис блокировок, старый клиент всё ещё может обратиться к ресурсу после проверки и выполнить запись.
Токены должны иметь порядок, который ресурс может надёжно сравнивать. Их генерация и сохранение состояния координационного сервиса также требуют устойчивости к перезапуску: повторная выдача уже использованного значения может нарушить защиту. При этом fencing token не исправляет повреждение данных, уже выполненную побочную операцию или неверную бизнес-логику — он предотвращает принятие устаревшей операции защищаемым ресурсом.
У подхода есть ограничения. Ресурс должен поддерживать передачу и проверку токена, а все опасные операции должны проходить через этот контроль. Если операция необратима и не допускает отклонения устаревшего запроса после его отправки, одного fencing token может быть недостаточно; потребуются идемпотентность, журналирование или компенсация.
Увеличение времени аренды уменьшает вероятность преждевременной потери блокировки, но не устраняет проблему полностью: пауза может оказаться дольше любой заранее выбранной длительности. Повторное получение блокировки после ошибки также не заменяет fencing tokens, поскольку старый клиент может продолжить работу независимо от результата нового захвата.
Сервис выбирает одного активного обработчика для обновления общего индекса. Обработчик A получает аренду и начинает формировать пакет изменений, но затем надолго приостанавливается. Аренда истекает, обработчик B получает блокировку, публикует новый индекс, после чего A возобновляется и пытается опубликовать устаревший пакет.
Рассматривались три варианта. Увеличить время аренды проще всего, но это лишь снижает вероятность конфликта и одновременно замедляет восстановление после отказа. Использовать только проверку владельца в сервисе блокировок недостаточно: между проверкой и публикацией может произойти смена владельца. Полагаться на версию самого индекса полезно для контроля изменений, но требует, чтобы публикация выполнялась атомарно относительно проверки версии.
Выбран вариант с монотонным токеном, который передаётся в хранилище индекса и проверяется атомарно при публикации. B получает токен 42 и успешно публикует индекс, а поздняя операция A с токеном 41 отклоняется. Дополнительно публикация сделана идемпотентной, чтобы повтор токена 42 не создавал побочных эффектов.
1. Почему продление аренды не является заменой fencing tokens?
Продление подтверждает, что клиент недавно связывался с координационным сервисом, но не отменяет уже выполняющуюся или задержанную операцию. Клиент может потерять возможность продлевать аренду, а затем возобновиться с устаревшей записью. Fencing token переносит проверку актуальности к ресурсу и потому защищает его от такого позднего запроса.
2. Где именно должна выполняться проверка fencing token?
Она должна выполняться на стороне ресурса, который принимает критическую операцию, либо в компоненте, атомарно контролирующем эту операцию. Проверка в клиенте ненадёжна, потому что клиент может быть устаревшим или скомпрометированным, а проверка в сервисе блокировок не синхронизирована автоматически с записью в ресурс. Если ресурс не умеет отклонять старые токены, токен не обеспечивает fencing, а служит лишь меткой для журналирования.
3. Достаточно ли сравнивать токены только на этапе начала длительной операции?
Не всегда. Если операция выполняется долго, после её начала может быть выдан более новый токен, и старый клиент всё ещё способен изменить ресурс или выполнить побочный эффект. Для критических операций контроль должен охватывать момент фактического изменения ресурса; для длительных процессов могут потребоваться повторная проверка, атомарная публикация результата или механизм отмены. Даже это не отменяет требования к идемпотентности и обработке частично выполненных действий.