При чтении ZooKeeper рецепта блокировки я смутился. Похоже, что этот рецепт для распределенных шлюзов не может гарантировать "любой моментальный снимок, когда два клиента не считают, что они имеют один и тот же замок" . Но так как ZooKeeper настолько широко принят, если в справочной документации были ошибки, кто-то должен был это указать давно, так что я понял неправильно?
Цитата рецепт для распределенных блокировок:
Блокировка
Полностью распределенные блокировки, которые глобально синхронны, значение при любом моментальном снимке, когда два клиента не считают, что они имеют ту же блокировку. Они могут быть реализованы с помощью ZooKeeeper. Как и в случае очередей приоритетов, сначала определите блокировку node.
- Вызовите create() с именем пути "locknode/guid-lock-" и установите последовательность и эфемерные флаги.
- Вызовите getChildren() на блокировке node без установки флага часов (это важно, чтобы избежать эффекта стада).
- Если путь, созданный на шаге 1, имеет суффикс с наименьшим порядковым номером, клиент имеет блокировку, и клиент выходит из протокола.
- Клиент вызывает exists() с флагом часов, установленным на пути в каталоге блокировки со следующим нижним порядковым номером.
- if exists() возвращает false, перейдите к шагу 2. В противном случае дождитесь уведомления для имени пути с предыдущего шага, прежде чем перейти к шагу 2.
Рассмотрим следующий случай:
- Клиент1 успешно приобрел блокировку (на шаге 3), с ZooKeeper node "locknode/guid-lock-0" ;
- Клиент2 создал node "locknode/guid-lock-1", не смог получить блокировку и теперь смотрит "locknode/guid-lock-0" ;
- Позже, по какой-либо причине (скажем, перегрузке сети), Client1 не может отправить сообщение о сердцебиении в кластер ZooKeeper вовремя, но Client1 все еще работает, ошибочно полагая, что он все еще удерживает блокировку.
-
Но ZooKeeper может подумать, что сеанс Client1 отключен, а затем
- удалить "locknode/guid-lock-0" ,
- отправить уведомление клиенту2 (или, может быть, сначала отправить уведомление?),
- но не может своевременно отправить уведомление "Тайм-аут сеанса" клиенту1 (скажем, из-за перегрузки сети).
- Клиент2 получает уведомление, переходит к шагу 2, получает единственный node "locknode/guid-lock-1", который он создал сам, поэтому Client2 предполагает, что он удерживает блокировку.
- Но в то же время Client1 предполагает, что он удерживает блокировку.
Является ли это допустимым сценарием?