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