Озабоченность по поводу рецепта замка

17

При чтении ZooKeeper рецепта блокировки я смутился. Похоже, что этот рецепт для распределенных шлюзов не может гарантировать «любой моментальный снимок, когда два клиента не считают, что они имеют один и тот же замок» . Но так как ZooKeeper настолько широко принят, если в справочной документации были ошибки, кто-то должен был это указать давно, так что я понял неправильно?

Задание рецепта для распределенных блокировок :

  

Блокировка      

Полностью распределенные блокировки, которые глобально синхронны, значение при любом моментальном снимке, когда два клиента не считают, что они имеют ту же блокировку . Они могут быть реализованы с помощью ZooKeeeper. Как и в случае очередей приоритетов, сначала определите узел блокировки.

     
  1. Вызовите create () с именем пути locknode / guid-lock- "и установите последовательность и эфемерные флаги.
  2.   
  3. Вызовите getChildren () на узле блокировки без установки флага часов (это важно, чтобы избежать эффекта стада).
  4.   
  5. Если путь, созданный на шаге 1, имеет суффикс с наименьшим порядковым номером, клиент имеет блокировку, и клиент выходит из протокола.
  6.   
  7. Клиент вызывает exists () с флагом часов, установленным на пути в каталоге блокировки со следующим нижним порядковым номером.
  8.   
  9. if exists () возвращает false, перейдите к шагу 2. В противном случае дождитесь уведомления для имени пути с предыдущего шага, прежде чем перейти к шагу 2.
  10.   

Рассмотрим следующий случай:

  • Клиент1 успешно приобрел блокировку (на шаге 3), с узлом ZooKeeper «locknode / guid-lock-0»;
  • Клиент2 создал узел «locknode / guid-lock-1», не смог получить блокировку и теперь смотрит «locknode / guid-lock-0»;
  • Позже, по какой-либо причине (скажем, перегрузке сети), Client1 не может отправить сообщение о сердцебиении в кластер ZooKeeper вовремя, но Client1 все еще работает, ошибочно полагая, что он все еще удерживает блокировку.
  • Но ZooKeeper может подумать, что сеанс Client1 отключен, а затем

    1. удалить "locknode / guid-lock-0",
    2. отправить уведомление клиенту2 (или, может быть, сначала отправить уведомление?),
    3. , но не может своевременно отправить уведомление «Тайм-аут сеанса» клиенту1 (скажем, из-за перегрузки сети).
  • Клиент2 получает уведомление, переходит к шагу 2, получает единственный узел «locknode / guid-lock-1», который он создал сам, поэтому Client2 предполагает, что он удерживает блокировку.
  • Но в то же время Client1 предполагает, что он удерживает блокировку.

Является ли это допустимым сценарием?

    
задан hulunbier 11.01.2013 в 10:56
источник
  • Параллельное обсуждение списка рассылки zookeeper-users: thread.gmane.org/gmane.comp.java.hadoop.zookeeper.user/5065 –  seh 10.04.2015 в 21:05

2 ответа

15

Сценарий, который вы описали, может возникнуть. Клиент 1 считает, что у него есть блокировка, но на самом деле его сеанс завершен, и клиент 2 получает блокировку.

Клиентская библиотека ZooKeeper сообщит клиенту 1, что его соединение отключено (но клиент не знает, что срок действия сеанса истек, пока клиент не подключится к серверу), поэтому клиент может написать код и предположить, что его блокировка был потерян, если он был слишком долго отключен. Но поток, который использует блокировку, должен периодически проверять, что блокировка по-прежнему действительна, что по своей природе является безупречным.

    
ответ дан sbridges 11.01.2013 в 15:32
  • спасибо; означает ли это, что «инвариант» - при любом снимке во времени ни один из двух клиентов не считает, что они сохраняют одну и ту же блокировку, не выполняется? –  hulunbier 11.01.2013 в 15:45
  • , что правильно –  sbridges 12.01.2013 в 04:22
  • Еще один тривиальный способ нарушить инвариант «во всех моментальных снимках во времени» (и, таким образом, доказать утверждение false) - это длительная пауза GC на клиенте, который удерживает блокировку. Например: клиент C получает блокировку, удерживая ее, java GC запускает и замораживает процесс в течение 60 секунд. Через 10 из этих секунд сеанс C истекает, а другой процесс получает блокировку. Время 11 - это «моментальный снимок во времени, когда 2 клиента считают, что они имеют один и тот же замок». –  Marco 29.01.2015 в 22:48
  • Просто нашел этот интересный пост: martin.kleppmann.com/2016/02/08/... –  zsxwing 03.06.2016 в 22:48
  • во время любого моментального снимка, когда два клиента не считают, что они хранят одну и ту же блокировку, основаны на следующих предположениях: ограниченная сетевая задержка, ограниченная пауза процесса и ограниченная ошибка синхронизации. –  zsxwing 03.06.2016 в 22:49
0
  

... Но Zookeeper может подумать, что сеанс client1 отключен, а затем ...

Из документации Zookeeper:

  
  • Удаление узла приведет к тому, что один клиент проснется с тех пор   каждый узел просматривается ровно одним клиентом. Таким образом, вы избегаете   стадо.
  •   
  • Нет опроса или тайм-аутов.
  •   

Итак, я не думаю, что проблема, которую вы описываете, возникает. Мне кажется, что существует риск зависания блокировок, если что-то происходит с клиентами, которые их создают, но сценарий, который вы описываете, не должен возникать.

    
ответ дан glenatron 11.01.2013 в 13:04
  • спасибо; но я не понимаю вашу идею; для меня «избегать стадного эффекта» && «без опроса или тайм-аутов» не может гарантировать, что клиент2 не может получить блокировку, а клиент1 удерживает блокировку. Кроме того, эфемерный узел будет автоматически удален ZK после окончания сеанса, поэтому я не вижу «риск зависания» ... –  hulunbier 11.01.2013 в 13:34
  • Если сеанс Client1 завершился, тогда блокировка больше не существует в этом случае, но Client1 будет получать SESSION_EXPIRED или CONNECTION_LOSS обратно из Zookeeper в это время, поэтому они будут знать, что они потеряли связь. –  glenatron 11.01.2013 в 14:55
  • Но что, если сообщение SESSION_EXPIRED не было отправлено клиенту 1 вовремя? Из-за временной высокой скорости потери пакетов, например (TCP-соединение остается ESTABLISHED) –  hulunbier 11.01.2013 в 15:32
  • вы получаете connection_loss, а не session_expired. Вы должны быть подключены к zookeeper, чтобы завершить сеанс. –  sbridges 12.01.2013 в 04:23