Consul, distributed locks и как мы с этим работаем (Lusnoc)
За последние пару лет Consul плотно вошёл в наш технологический стэк. Сначала как хранилище конфигурации потом как service provider для внутренних систем таких как prometeus и traefik и наконец как инструмент для distributed locks и leader election. В конце я еще приведу список полезных ссылок по теме с комментариями, а пока речь пойдет о нашей Ruby библиотеке, реализующей семантику мьютекса поверх функционала, предоставляемого Consul’ом. Библиотека, она же гем, получила название Lusnoc.
Что это такое и зачем оно надо?
В процесса работы нам потребовалось гарантировать выполнение кода только одним процессом (сервисом) и избежать гонок. Поскольку существует уже веками устоявшийся примитив мьютекс было решено реализовать функционал именно в таком виде. В Ruby для этого существует стандартный класс Mutex и мы сделали всё аналогично.
Основная задача библиотеки Lusnoc - реализация распределенного механизма для блокировки ресурса.
Библиотека задумывалась как простая в использовании, надёжная и без “черной магии” под капотом. Когда создавалась эта библиотека ещё был жив проект consul-mutex
(сейчас его выпилили, но сохранился мой форк). Беда была в том, что он совершал слишком много фоновой магии и автоматизировал то, что на мой взгляд автоматизировать не стоит.
Чем Lusnoc лучше других решений?
Прежде всего “других” решений не так много, а те что есть обладают рядом проблем (например блокировки поверх redis как самописные так и использующие алгоритм redlock). А красивых и надёжных, использующих кластер Consul нет совсем.
Что насчет consul-mutex или diplomat?
- Во-первых consul-mutex уже канул в лету
- Во вторых он создавал фоновый поток в котором исполнял ваш код и мог прибить его в любое время без предупреждения, если считал что владение ресурсом потеряно
- С гемом diplomat всё проще — он предоставляет лишь базовую реализацию API для работы с сессиями Consul и никакого механизма по управлению ими
На Ruby есть реализации блокировок с использованием Zookeeper, Etcd и пр. но мы их не рассматривали, поскольку Consul уже прописался в нашей инфраструктуре.
Чем же так хорош Lusnoc что его стоит использовать?
Начнем с того что он использует надёжный механизм создания сессий в Consul и привязанные к нему ключи в K/V хранилище. Таким образом при потере связи с кластером или другой нештатной ситуации сессия будет автоматически завершена на стороне консула и ресурс разблокируется. На языке руби можно сказать что сессия создаётся перед выполнением блока (критической секции) и уничтожается после:
При создании сессий используется TTL и через него общий ресурс защищен от зависания вашего кода и прочих трудно воспроизводимых но очень распространенных вещей.
Lusnoc задумывался как максимально простой и понятный - "Keep it simple, stupid"
Библиотека Lusnoc не делает за вас “умных” действий — например обновление сессии необходимо выполнять руками внутри критической секции и не прозевать момент когда сессия протухнет. Для помощи в этом нелегком деле фоновый поток всё же запускается, но он имеет “консультативный” характер и не прибьёт рабочий поток без предупреждения.
И последнее — гем использует весьма эффективные блокирующие запросы к Consul для реализации мгновенной реакции на изменение состояния сессии, таймаут занятия блокировки или реакции на ручное удаление блокировки админом. Именно для ожидания таких событий используется фоновый поток.
Как использовать?
Что на выходе?
В результате мы имеем привычную для любого разработчика семантику мьютексов, позволяющую просто и понятно выполнять достаточное сложные действия — например leader election
или просто иметь строгую гарантию выполнения определенного действия строго одним процессом.
О конкретном примере использования данной библиотеки я напишу в следующей статье, а напоследок список полезных материалов по теме:
- https://www.consul.io/ —про Consul
- https://codeblog.dotsandbrackets.com/consul-key-value-store-configuration/ — маленькая статья о том как использовать Consul для хранения конфигурации. Мы используем KV для инициализации переменных окружения при запуске контейнеров (12 factor application и все дела)
- https://learn.hashicorp.com/tutorials/consul/distributed-semaphore — реализация распределенных блокировок через Consul
- https://learn.hashicorp.com/tutorials/consul/application-leader-elections — реализация процедуры выбора лидера через Consul
- https://redis.io/topics/distlock — реализация блокировок через Redis и
redlock
алгоритм. Очень интересно. Рассматривает проблемы multi-master и пр. - http://martin.kleppmann.com/2016/02/08/how-to-do-distributed-locking.html — анализ предыдущего алгоритма
redlock
от Мартина Клепмана ❗️ - http://antirez.com/news/101 — анализ анализа и ответ Мартину Клепману 😆