Redis реализует распределенные блокировки

Redis

Раньше запланированные задачи, которые мы использовали, развертывались только на одной машине.Чтобы решить проблему одной точки, чтобы гарантировать выполнение задачи только одной машиной, нам нужно рассмотреть проблему блокировок, поэтому мы потратили время на изучение этой проблемы. Как реализовать распределенную блокировку?

Суть замка в томвзаимоисключающий, чтобы гарантировать, что клиент может удерживать одну и ту же блокировку в любое время.Если вы планируете использовать Redis для реализации распределенной блокировки, самое простое решение — создать значение ключа в экземпляре и удалить значение ключа при снятии блокировки. Но надежная и полная распределенная блокировка требует учета многих деталей, давайте посмотрим, как написать правильную распределенную блокировку.

Автономный распределенный замок SETNX

Поэтому мы реализуем простую блокировку непосредственно на основе команды setNX (SET if Not eXists) redis. Псевдокод напрямую

Получение блокировки:

    SET resource_name my_random_value NX PX 30000

Разблокировка блокировки:

    if redis.call("get",KEYS[1]) == ARGV[1] then
        return redis.call("del",KEYS[1])
    else
        return 0
    end

Несколько деталей на заметку:

  • Во-первых, нам нужно установить период ожидания при получении блокировки. Тайм-аут установлен для предотвращения сбоя клиента или удержания блокировки после сетевой проблемы. Система зашла в тупик.
  • Используйте команду setNX, чтобы убедиться, что два шага запроса и записи являются атомарными.
  • Когда замок снят, мы судимKEYS[1]) == ARGV[1],это здесьKEYS[1]это значение, взятое из redis,ARGV[1]генерируется вышеmy_random_value. Причина вынесения вышеуказанного суждения заключается в том, чтобы убедиться, чтоЗамок открывается держателем замка. Будем считать, что этот шаг проверки не выполняется:

    1. Клиент A получает блокировку, и поток сообщений зависает. Время больше, чем время истечения блокировки.
    2. По истечении срока блокировки клиент B получает блокировку.
    3. После восстановления клиент A обрабатывает связанные события и отправляет команду del в redis. замок снят
    4. Клиент C получает блокировку. В это время два клиента в системе одновременно удерживают блокировки.

      Ключ к этой проблеме заключается в том, что блокировка, удерживаемая клиентом B, снимается клиентом A.

  • разблокировка замкадолженИспользуйте сценарии lua для обеспечения атомарности операций. Разблокировка замка включает в себяget,судить,delтри шага. Если невозможно гарантировать атомарность трех шагов, у распределенных блокировок возникнут проблемы параллелизма.

Обращая внимание на приведенные выше детали, достигается распределенная блокировка одного узла Redis.

В этой распределенной блокировке все еще есть единственная точка redis. Вы можете сказать, что Redis — это архитектура master-slave, и хорошо переключаться на slave в случае сбоя, но репликация Redis асинхронна.

  • Если клиент А получает блокировку на мастере.
  • Прежде чем мастер синхронизирует данные с ведомым, мастер отключается.
  • Клиент B снова получает блокировку от ведомого устройства.

Таким образом, из-за простоя мастера несколько человек одновременно держат замок. Если ваша система доступна, примите несколько человек, удерживающих замок в течение короткого периода времени. Это простое решение решит проблему.

Но если решить эту проблему. Официальный Redis предоставляет решение Redlock.

Второй реализует RedLock

Для того, чтобы решить проблему единой точки Redis. Автор Redis придумал решение для RedLock. Схема очень гениальная и лаконичная.
Основная идея RedLock заключается в одновременном использовании нескольких мастеров Redis для резервирования, причем эти узлы полностью независимы, и нет необходимости синхронизировать данные между этими узлами.

Предположим, у нас есть N узлов Redis, N должно быть нечетным числом больше 2. Этапы внедрения RedLock:

  1. получить текущее время
  2. Используйте метод, упомянутый выше, для последовательного получения блокировок Redis для N узлов.
  3. Если количество полученных блокировок больше (N/2+1), а время получения меньше времени действия блокировки, считается, что получена действующая блокировка. Время автоматического снятия блокировки равно первоначальному времени снятия блокировки за вычетом времени, затраченного на получение блокировки.
  4. Если количество полученных блокировок меньше, чем (N/2+1), или если в течение времени действия блокировки не получено достаточное количество блокировок, считается, что получение блокировки не удалось. В это время сообщение об освобождении блокировки должно быть отправлено всем узлам.

Реализация снятия блокировки очень проста. Я хочу, чтобы все узлы Redis инициировали операцию освобождения, независимо от того, была ли блокировка успешно получена или нет.

В то же время, есть несколько деталей, на которые следует обратить внимание:

  • Интервал между попытками получить блокировку должен быть случайным диапазоном, а не фиксированным временем. Это может помешать нескольким клиентам одновременно отправлять операции получения блокировки в кластер Redis, чтобы избежать одновременной конкуренции. Когда одинаковое количество замков приобретается одновременно. (хотя вероятность очень мала)
  • В случае сбоя главного узла интервал времени восстановления должен быть больше, чем время действия блокировки.

    1. Предположим, что есть три узла Redis A, B и C.
    2. Клиент foo получает две блокировки A и B.
    3. В это время B отключен, и все данные в памяти потеряны.
    4. Узел Б отвечает.
    5. В это время панель клиента повторно захватывает блокировку и получает два узла B и C.
    6. На данный момент еще два клиента получили блокировку.

      Поэтому, если время восстановления будет больше, чем время действия блокировки, вышеописанной ситуации можно избежать. В то же время, если требования к производительности не высоки, вы даже можете включить опцию сохраняемости Redis.

Суммировать

После понимания распределенной реализации Redis я на самом деле чувствую, что большинство распределенных систем в принципе очень просты, но для обеспечения надежности распределенных систем нам нужно обращать внимание на многие детали и тривиальные исключения.
Распределенная блокировка, реализованная алгоритмом RedLock, проста и эффективна, а идея весьма умна.
Но обязательно ли RedLock безопасен? Я также напишу статью, чтобы обсудить этот вопрос. Пожалуйста, с нетерпением ждите этого,Адрес статьи.