Открыть сервис

Алгоритм распределённой блокировки

Алгоритм распределённой блокировки — это метод синхронизации доступа к общему ресурсу (данным, файлу, устройству, критической секции кода) в распределённой вычислительной системе, где несколько независимых узлов (процессов, серверов, контейнеров) взаимодействуют через сеть. В отличие от блокировок в однопроцессорных системах (мьютексы, семафоры), распределённые блокировки должны учитывать задержки сети, возможные сбои узлов, отсутствие общей памяти и необходимость достижения консенсуса между участниками. Основная цель алгоритма — гарантировать взаимное исключение (mutual exclusion): в любой момент времени только один узел может владеть блокировкой и выполнять операции над защищаемым ресурсом.

История и предпосылки

Необходимость в распределённых блокировках возникла с развитием распределённых баз данных, файловых систем (например, NFS, AFS) и кластерных вычислений в 1970–1980-х годах. Классические алгоритмы взаимного исключения, такие как алгоритм Деккера или Петерсона, работают только при наличии общей памяти, что неприменимо в сетевой среде. Первые теоретические решения для распределённых систем были предложены в работах Г. Л. Рикарта и А. К. Агравалы (1981), а также в алгоритме на основе токена (token ring). С развитием интернет-сервисов и микросервисной архитектуры в 2000–2010-х годах распределённые блокировки стали ключевым компонентом таких систем, как Apache ZooKeeper, etcd, Redis Redlock, Amazon DynamoDB Lock Client и Google Chubby.

Классификация алгоритмов

Алгоритмы распределённой блокировки можно разделить по нескольким критериям:

По способу координации

  1. Централизованные (с выделенным координатором): Один узел (сервер блокировок) управляет всеми блокировками. Клиенты отправляют запросы на захват и освобождение блокировки координатору. Примеры: ZooKeeper (эпемерные узлы), Chubby. Просты в реализации, но координатор становится единой точкой отказа и узким местом производительности.
  2. Децентрализованные (без единого координатора): Узлы договариваются о блокировке через обмен сообщениями. Примеры: алгоритм Рикарта — Агравалы, алгоритм на основе токена. Более отказоустойчивы, но требуют сложных протоколов консенсуса и большего числа сообщений.
  3. Распределённые на основе консенсуса: Используют протоколы достижения согласия (например, Paxos, Raft) для выбора владельца блокировки. Примеры: etcd (Raft), Consul (Raft). Сочетают надёжность централизованного подхода с отказоустойчивостью.

По типу блокировки

  • Эксклюзивные (write lock): Только один узел может владеть блокировкой.
  • Разделяемые (read lock): Несколько узлов могут одновременно владеть блокировкой для чтения, но не для записи.
  • Рекурсивные: Узел может повторно захватить блокировку, уже удерживаемую им.
  • Блокировки с тайм-аутом (lease): Блокировка автоматически освобождается по истечении заданного времени, что предотвращает «вечное» удержание при сбое узла.

По гарантиям корректности

  • Безопасность (safety): В любой момент времени блокировку удерживает не более одного узла (в случае эксклюзивной блокировки).
  • Живучесть (liveness): Если узел запрашивает блокировку, он в конечном счёте её получит (при отсутствии сбоев).
  • Отказоустойчивость: Алгоритм продолжает работать при сбоях части узлов (обычно до f из n узлов, где f — допустимое число отказов).

Основные алгоритмы

Алгоритм Рикарта — Агравалы (Ricart–Agrawala)

Предложен в 1981 году. Основан на обмене сообщениями: каждый узел, желающий захватить блокировку, рассылает запрос всем остальным узлам. Узел, получивший запрос, отвечает согласием, если сам не удерживает блокировку и не запрашивает её с более высоким приоритетом (по времени запроса). Когда узел получает согласие от всех, он захватывает блокировку. Требует O(n) сообщений на одну операцию (n — число узлов). Гарантирует взаимное исключение и свободу от голодания, но не устойчив к сбоям узлов.

Алгоритм на основе токена (Token Ring)

Узлы логически объединены в кольцо. По кольцу циркулирует уникальный токен. Узел может захватить блокировку только когда владеет токеном. После завершения работы узел передаёт токен следующему узлу. Прост и требует O(1) сообщений в среднем, но при потере токена (например, из-за сбоя узла) требуется механизм его восстановления, что усложняет систему.

Алгоритм с использованием эпемерных узлов (ZooKeeper)

В ZooKeeper (организация Apache Software Foundation) блокировка реализуется через создание временного (эпемерного) узла (znode) с уникальным именем. Клиент создаёт узел в определённой директории. Если узел создан успешно, клиент получает блокировку. Если узел уже существует, клиент подписывается на событие его удаления. При освобождении блокировки (или сбое клиента) эпемерный узел автоматически удаляется, и следующий клиент получает уведомление. Этот подход обеспечивает отказоустойчивость и простоту, но требует работы ZooKeeper-ансамбля (минимум 3 узла для отказоустойчивости).

Redlock (Redis)

Предложен разработчиками Redis (Salvatore Sanfilippo) в 2015 году для распределённых блокировок на основе Redis. Алгоритм предполагает наличие N независимых Redis-узлов (обычно 5). Клиент последовательно пытается установить блокировку на каждом узле с одинаковым ключом и уникальным значением (например, UUID). Блокировка считается успешно захваченной, если клиент получил ответ от большинства узлов (N/2 + 1) в течение заданного времени (тайм-аута). Для освобождения блокировки клиент отправляет команду DEL на все узлы. Redlock критикуется за потенциальные проблемы с синхронизацией времени и неполную гарантию безопасности в некоторых сценариях (например, при перезапуске узлов), но широко используется на практике.

Алгоритмы на основе консенсуса (Raft, Paxos)

В системах, таких как etcd или Consul, блокировка реализуется через транзакции, поддерживаемые протоколом Raft. Клиент отправляет запрос на запись (например, создание ключа с определённым значением) в кластер. Если запрос коммитится (достигает консенсуса), блокировка считается захваченной. При освобождении ключ удаляется. Эти алгоритмы обеспечивают строгую согласованность (linearizability) и отказоустойчивость, но требуют большего времени на операцию из-за необходимости записи на диск и обмена сообщениями между узлами.

Применение

Распределённые блокировки используются в следующих областях:

Критика и ограничения

  • Проблема «split-brain»: При сетевом разделении (partition) разные части системы могут одновременно считать, что владеют блокировкой, что приводит к нарушению взаимного исключения. Алгоритмы на основе консенсуса (Raft) решают эту проблему, требуя кворума.
  • Зависимость от времени: Алгоритмы, использующие тайм-ауты (например, Redlock), могут давать сбои при несинхронизированных часах на узлах.
  • Производительность: Централизованные решения могут стать узким местом при высокой нагрузке. Децентрализованные алгоритмы требуют большого числа сетевых сообщений.
  • Сложность отладки: Ошибки в реализации распределённых блокировок трудно воспроизвести и диагностировать из-за асинхронности и недетерминизма.

Интересные факты

  • Алгоритм Рикарта — Агравалы является одним из первых строго доказанных решений задачи взаимного исключения в распределённых системах.
  • Google Chubby, описанный в 2006 году, использовал распределённые блокировки на основе Paxos и стал основой для многих современных систем, включая Apache ZooKeeper.
  • В 2016 году Redis Labs выпустила библиотеку Redlock-py, которая была подвергнута критике со стороны экспертов по распределённым системам (например, Мартина Клеппмана) за потенциальные уязвимости.

Источники

  • Ricart, G., & Agrawala, A. K. (1981). An optimal algorithm for mutual exclusion in computer networks. Communications of the ACM, 24(1), 9–17.
  • Burrows, M. (2006). The Chubby lock service for loosely-coupled distributed systems. Proceedings of the 7th symposium on Operating systems design and implementation.
  • Hunt, P., Konar, M., Junqueira, F. P., & Reed, B. (2010). ZooKeeper: Wait-free coordination for internet-scale systems. USENIX Annual Technical Conference.
  • Redlock: Distributed locks with Redis. Redis documentation (2015).
  • Ongaro, D., & Ousterhout, J. (2014). In search of an understandable consensus algorithm. USENIX Annual Technical Conference.
  • Kleppmann, M. (2016). How to do distributed locking. Martin Kleppmann's blog.

BFOmetr — база данных и аналитика по компаниям России.

На главную BFOmetr →