Вездесущие замки, квалифицированные в Redis

Чтобы обеспечить правильность одновременного доступа, Redis предоставляет два метода, а именно блокировку и атомарную операцию.

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

Первый: атомарные операции без блокировок

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

1. Что нужно контролировать при параллельном доступе?

1.1 Что такое одновременный контроль доступа?
Он относится к управлению процессом доступа нескольких клиентов к одним и тем же данным и работе с ними, чтобы гарантировать, что операции, отправляемые любым клиентом, являются взаимоисключающими при выполнении на экземпляре Redis. Например, когда выполняется операция доступа клиента А, операция клиента Б не может быть выполнена, а операция клиента Б не может быть выполнена до тех пор, пока операция клиента А не будет завершена.
Операции, соответствующие одновременному управлению доступом, в основном являются операциями модификации данных. Когда клиенту необходимо изменить данные, основной процесс делится на два этапа:
1. Сначала клиент считывает данные локально и изменяет их локально,
2. После того, как клиент изменяет данные, он записывает их обратно в Redis.
Этот процесс называется операцией «чтение-изменение-обратная запись» (Read-Modify-Write, называемая операцией RMW). Когда несколько клиентов выполняют операции RMW с одними и теми же данными, пусть коды, участвующие в операциях RMW, выполняются атомарно. Код операции RMW, который обращается к тем же данным, называется кодом критической секции. Когда несколько клиентов одновременно выполняют код критической секции, возможны некоторые проблемы.

1.2 Пример клиента, обновляющего товарный запас:
Предположим, что клиент хочет выполнить операцию вычета 1 в товарном запасе, псевдокод выглядит следующим образом:

current = GET(id)
current--
SET( id,current)

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

Если нет механизма контроля выполнения кода критической секции, возникнут ошибки обновления данных. В предыдущем примере, если предположить, что два клиента A и B одновременно выполняют код критической секции, произойдет ошибка:
вставьте сюда описание изображения

При обработке в соответствии с правильной логикой каждый клиент A и B вычитает стоимость инвентаря один раз, и значение инвентаря должно быть равно 8. Таким образом, стоимость запасов здесь явно обновлена ​​неправильно.
Причина этого явления заключается в том, что клиент в коде критической секции включает три операции для чтения данных, обновления данных и обратной записи данных, и эти три операции не являются взаимоисключающими при выполнении, несколько клиентов изменяют на основе одного и того же начального значения, а не на основе значения, измененного предыдущим клиентом.

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

LOCK()
current = GET(id)
current--

Хотя блокировка обеспечивает взаимную исключительность, блокировка также снижает производительность системы при параллельном выполнении.
Как показано на рисунке ниже, когда клиент A блокирует и выполняет операции, клиентам B и C приходится ждать. После того, как A снимает блокировку, предполагая, что B получает блокировку, C все еще должен продолжать ждать. Следовательно, только A может получить доступ к общим данным в течение периода t1, и только B может получить доступ к общим данным в течение периода t2. конечно, производительность параллелизма системы упадет.
вставьте сюда описание изображения

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

2. Два атомарных метода работы Redis

Чтобы добиться взаимоисключающего выполнения кода критической секции, необходимого для управления параллелизмом, атомарные операции Redis используют два метода:

  1. Реализовать несколько операций в одну операцию в Redis, то есть операцию одной команды;
  2. Запишите несколько операций в сценарий Lua и атомарно выполните один сценарий Lua.

2.1 Однокомандная работа самого Redis.
Redis использует один поток для последовательной обработки команд операции запроса клиента, поэтому, когда Redis выполняет определенную командную операцию, другие команды не могут быть выполнены, что эквивалентно тому факту, что командные операции являются взаимоисключающими. Конечно, операции генерации снапшотов Redis и операции перезаписи AOF могут выполняться с помощью фоновых потоков или подпроцессов, то есть они выполняются параллельно с операциями основного потока. Однако эти операции только считывают данные, не изменяют данные и не требуют для них управления параллелизмом.
Хотя одна командная операция Redis может выполняться атомарно, в практических приложениях модификация данных может включать в себя несколько операций, включая как минимум три операции чтения данных, добавления и вычитания данных и обратной записи данных, что, очевидно, не является одной командной операцией. Теперь, что мне делать?
Операции добавления/уменьшения стоимости выполняются, и они являются одной командной операцией. Когда Redis выполняет их, они взаимоисключающие.
Например, в только что приведенном примере вычета запасов клиент может использовать следующий код, чтобы напрямую выполнить операцию вычитания 1 из стоимости запасов идентификатора продукта. Даже если несколько клиентов выполняют следующий код, не нужно беспокоиться об ошибках вычета стоимости запасов.

decr id

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

2.2 Lua-скрипт:
Redis выполнит весь Lua-скрипт как единое целое. Он не будет прерываться другими командами во время выполнения, что обеспечивает атомарность операций в Lua-скриптах. Необходимо выполнить несколько изменений, которые не могут быть реализованы с помощью командных операций, таких как INCR / DECR.Вы можете записать выполненные операции в сценарий Lua, и вы можете использовать команду EVAL Redis для выполнения сценария. Таким образом, эти операции являются взаимоисключающими при выполнении.

2.3 Пример использования Lua:
когда количество пользователей доступа к бизнес-приложению увеличивается, иногда необходимо ограничить количество посещений определенного клиента в течение определенного периода времени, например, текущий лимит покупки популярных продуктов и количество лайков в минуту в социальных сетях ограничения и т.д.
Итак, как его ограничить?
Вы можете использовать IP-адрес клиента в качестве ключа и количество посещений клиента в качестве значения и сохранить его в Redis. После каждого визита клиента мы используем INCR для увеличения количества посещений.
В этом сценарии лимит трафика на стороне клиента фактически включает ограничения на количество посещений и временной диапазон, например, количество посещений в минуту не может превышать 20. Вы можете установить время истечения срока действия для соответствующей пары ключ-значение при первом доступе клиента, например, установить срок действия через 60 секунд.
Каждый раз, когда клиент посещает, читайте текущее количество посещений клиента.Если число превышает пороговое значение, будет сообщено об ошибке, и клиенту будет запрещено повторное посещение.

//获敏ip对应的访同次数
current = GET(ip)
//如果超过访问次数超过20次,则报错
IF current != NULL  AND current >20 THEN
		ERROR "exceed 20 accesses persecond"
ELSE
    //如果访问次数不定20次,增加一次访问计数
    value = INCR(ip)
    //如果是第一次访间,将键值对的过期时间设置为60s后
		IF value == 1  THEN
      EXPiRE(ip,60)
	  END
    //执行其他噪作
		DO THINGS

В этом примере INCR используется для атомарного увеличения счетчика. Однако логика ограничения тока на стороне клиента включает в себя не только подсчет, но также оценку количества доступов и настройку времени истечения срока действия. Для этих операций также необходимо обеспечить их атомарность.

В противном случае, если клиент использует многопоточный доступ, начальное значение количества посещений равно 0. После того, как первый поток выполнит операцию INCR(ip), второй поток также выполнит INCR(ip). ip Количество посещений увеличено до 2, и мы больше не можем устанавливать время истечения для этого ip. Это приведет к тому, что после того, как количество посещений клиента, соответствующего этому ip, достигнет 20 раз, он больше не сможет посещать. Даже по истечении 60 секунд вы уже не сможете продолжить посещение, что явно не соответствует бизнес-требованиям.

Поэтому операция в этом примере не может быть реализована с помощью одной команды Redis.На этом этапе мы можем использовать сценарии Lua для обеспечения контроля параллелизма. Мы можем написать три операции: добавить 1 к количеству посещений, определить, равно ли количество посещений 1, и установить время истечения срока действия в сценарии Lua, как показано ниже:

local current

current = redis.call ( "incr", KEYS[1])
if tonumber (current) == 1 then
		redis.call( "expire" , KEYS[1],60)
end

Предполагая, что имя написанного сценария — lua.script, вы можете использовать клиент Redis с параметром eval для выполнения сценария. Параметры, необходимые сценарию, будут передаваться через ключи и аргументы в следующих командах.
redis-cli --eval lua.script keys , args
Таким образом, три операции добавления 1 к количеству посещений, определение того, равно ли количество посещений 1, и установка времени истечения срока действия могут быть выполнены атомарно. Даже если клиент имеет несколько потоков, выполняющих скрипт одновременно, Redis будет выполнять код скрипта последовательно, избегая ошибок данных, вызванных параллельными операциями.

3. Обзор безблокировочных атомарных операций

При одновременном доступе одновременные операции RMW (чтение-изменение-запись) вызовут ошибки данных, поэтому требуется контроль параллелизма. Так называемый контроль параллелизма должен обеспечить взаимоисключающее выполнение кода критической секции.

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

Однако область применения однокомандных атомарных операций невелика, и не все операции RMW могут быть преобразованы в однокомандные атомарные операции (например, команды INCR/DECR могут выполнять только атомарное увеличение или уменьшение после считывания данных), и необходимо читать. Когда делается больше суждений о данных или когда модификация данных не является простым увеличением или уменьшением, однокомандная операция не применяется.

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

Когда Redis выполняет Lua-скрипты, он может гарантировать атомарность.Тогда в примере с Lua-скриптом (lua.script), который я привел, считаете ли вы, что нужно читать количество посещений ip клиента, то есть GET(ip) , и логика оценки того, превышает ли количество посещений 20, также добавлена ​​в сценарий Lua?

Ответ: В этом примере есть три операции для обеспечения атомарности, а именно: INCR, определение того, равно ли количество посещений 1, и установка времени истечения срока действия. Для двух операций получения IP и оценки того, превышает ли количество посещений 20, это только операции чтения.Даже если у клиента есть несколько потоков, выполняющих эти две операции одновременно, никакое значение не будет изменено, поэтому нет необходимости гарантировать атомарность. ., не помещая их в скрипты Lua.

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

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

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

1. Связь и отличие блокировок на одной машине от распределенных блокировок

1.1 Блокировки на одной машине
Для многопоточной программы, работающей на одной машине, сама блокировка может быть представлена ​​переменной.

  • Когда значение переменной равно 0, это означает, что ни один поток не получает блокировку;
  • Когда значение переменной равно 1, это означает, что поток получил блокировку.

1.1.1 Инструкции для потоков по вызову блокировки и снятию блокировки
Блокировка
На самом деле, когда поток вызывает операцию блокировки, он фактически проверяет, равно ли значение переменной блокировки 0.
Если это 0, установите значение переменной блокировки в 1, указывая, что блокировка была получена.
Если он не равен 0, возвращается сообщение об ошибке, указывающее, что блокировка не удалась, и другой поток уже получил блокировку.
Освобождение блокировки
Когда поток вызывает операцию освобождения блокировки, он фактически устанавливает значение переменной блокировки в 0, чтобы другие потоки могли получить блокировку.
Операции добавления и снятия блокировок, где lock — переменная блокировки.

acquire__lock(){
    
    
  if lock ==0
     lock = 1
  	 return 1
	else
     return 0
}
release__lock(){
    
    
if lock = 0
  	return 1
}

1.1.2 Сходства между автономными блокировками и распределенными блокировками:
Подобно блокировкам на автономной машине, распределенные блокировки также могут быть реализованы с помощью переменной. Логика операции блокировки и снятия блокировки на стороне клиента также согласуется с логикой операции блокировки и снятия блокировки на отдельной машине: при блокировке необходимо оценивать значение переменной блокировки и определять, блокировка может быть успешно заблокирована в соответствии со значением переменной блокировки; при блокировке значение переменной блокировки должно быть установлено на 0, что указывает на то, что клиент больше не удерживает блокировку.

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

1.2 Два требования для реализации распределенных блокировок.

  1. Требование 1. Процесс блокировки и снятия распределенной блокировки включает несколько операций. Поэтому при реализации распределенных блокировок необходимо обеспечить атомарность операций этих блокировок;
  2. Требование 2: Общая система хранения сохраняет переменную блокировки.Если общая система хранения выходит из строя или выходит из строя, клиент не может выполнить операцию блокировки. При реализации распределенных блокировок необходимо учитывать обеспечение надежности системы общего хранения, тем самым обеспечивая надежность блокировки.
    Его можно реализовать на основе одного узла Redis или с использованием нескольких узлов Redis. В этих двух случаях надежность замка не одинакова

2. Реализуйте распределенную блокировку на основе одного узла Redis.

В качестве общей системы хранения в процессе реализации распределенных блокировок Redis может использовать пары «ключ-значение» для хранения переменных блокировки, а затем получать и обрабатывать запросы на блокировку и освобождение, отправленные разными клиентами.
2.1 Ключ и значение пары ключ-значение определяются путем
присвоения имени переменной блокирующей переменной в качестве ключа пары ключ-значение — «значение блокирующей переменной используется как значение пары ключ-значение». — «Redis может сохранить переменную блокировки, и клиент также может. Операция блокировки может быть реализована с помощью командной операции Redis.
Он показывает, что Redis использует пары ключ-значение для сохранения переменных блокировки и процесса работы двух клиентов, одновременно запрашивающих блокировки.

Видно, что Redis может использовать пару ключ-значение lock_key:0 для сохранения переменной блокировки, где ключ — это lock_key, который также является именем переменной блокировки, а начальное значение переменной блокировки равно 0.

2.2 Операция блокировки:
на рисунке клиенты A и C одновременно запрашивают блокировку. Поскольку Redis использует один поток для обработки запросов, даже если клиенты A и C одновременно отправляют Redis запросы на блокировку, Redis будет обрабатывать их запросы последовательно.

Предположим, что Redis сначала обрабатывает запрос клиента A, считывает значение lock_key и обнаруживает, что lock_key равен 0, поэтому Redis устанавливает значение lock_key равным 1, указывая, что он заблокирован. Сразу после этого Redis обрабатывает запрос клиента C. В это время Redis обнаружит, что значение lock_key уже равно 1, поэтому возвращает сообщение о сбое блокировки.

2.3 Операция снятия блокировки
Чтобы снять блокировку, необходимо напрямую установить значение переменной блокировки в 0.
На рисунке ниже показан процесс запроса клиента A на снятие блокировки. Когда клиент A удерживает блокировку, значение переменной блокировки lock_key равно 1. После того, как клиент A выполнит операцию снятия блокировки, Redis устанавливает значение lock_key равным 0, указывая на то, что ни один клиент больше не удерживает блокировку.

Блокировка включает в себя три операции (чтение переменной блокировки, оценка значения переменной блокировки и установка значения переменной блокировки в 1), и эти три операции должны обеспечивать атомарность во время выполнения.

2.4 Как обеспечить атомарность заблокированных данных:
Для обеспечения атомарности операций существует два основных метода, а именно использование однокомандных операций Redis и использование скриптов Lua.
Атомарность: Атомарность означает, что операция либо выполняется успешно, либо не выполняется вообще, и нет промежуточного состояния. Другими словами, атомарность может гарантировать, что ряд операций представляет собой неделимое целое, либо все они выполняются успешно, либо все они терпят неудачу, тем самым обеспечивая непротиворечивость и целостность данных.

Как следует применять эти два метода в сценарии распределенной блокировки?
2.4.1 Какие однокомандные операции Redis может использовать для реализации операций блокировки: SETNX и del
Первая — это команда SETNX, которая используется для установки значения ключа -ценная пара. В частности, эта команда определит, существует ли пара ключ-значение при ее выполнении. Если она не существует, установите значение пары ключ-значение. Если она существует, она не будет выполнять никаких настроек.

Например, если ключ не существует, когда выполняется следующая команда, ключ будет создан, и значение будет установлено в значение; если ключ уже существует, SETNX не будет выполнять никакого назначения.

SETNX key value

Для операции снятия блокировки вы можете использовать команду DEL для удаления переменной блокировки после выполнения бизнес-логики. Не беспокойтесь о том, что после удаления переменной блокировки другие клиенты не смогут запросить ее блокировку.
Поскольку при выполнении команды SETNX, если пара ключ-значение (то есть переменная блокировки), которую нужно установить, не существует, команда SETNX сначала создаст пару ключ-значение, а затем установит ее значение. Поэтому после снятия блокировки, когда клиент снова запрашивает блокировку, команда SETNX создаст пару ключ-значение для сохранения переменной блокировки и установит значение переменной блокировки для завершения блокировки.
Подводя итог, можно использовать комбинацию команд SETNX и DEL для реализации операций блокировки и снятия блокировки. В следующем примере псевдокода показана операция блокировки

/加锁
SETNX lock_key 1
/业务逻辑
Do THINGS
//释放锁
DEL lock_key

2.4.2 Использование комбинации команд SETNX и DEL для реализации распределенных блокировок сопряжено с двумя потенциальными рисками.
Первый риск
Если клиент выполняет команду SETNX и блокируется, возникает исключение при работе с общими данными, и в результате не выполняется последняя команда DEL для снятия блокировки. Таким образом, этот клиент всегда удерживает блокировку, а другие клиенты не могут получить блокировку, получить доступ к общим данным и выполнить последующие операции, что повлияет на бизнес-приложения.
Эффективным решением является установка времени истечения для переменной блокировки. Таким образом, даже если клиент, удерживающий блокировку, имеет исключение и не может активно снять блокировку, Redis удалит переменную блокировки после истечения срока ее действия в соответствии со временем истечения переменной блокировки. После истечения срока действия переменной блокировки другие клиенты могут снова запросить блокировку, поэтому не будет проблем с невозможностью блокировки.

Второй риск
Если клиент A выполняет команду SETNX для блокировки, предполагая, что клиент B выполняет команду DEL для снятия блокировки, в это время блокировка клиента A снимается по ошибке. Если клиент C подает заявку на блокировку, он может успешно получить блокировку, а затем начать работать с общими данными. Таким образом. Клиенты A и C работают с общими данными одновременно, и данные будут изменены неправильно, что также неприемлемо для бизнес-уровня.
Необходимо уметь различать операции блокировки от разных клиентов,
это можно обработать по значению переменной блокировки:
в методе блокировки с помощью команды SETNX, установив значение переменной блокировки в 1 или 0, это указывает, успешна ли блокировка. 1 и 0 имеют только два состояния, которые не могут указывать, какой клиент выполняет операцию блокировки. Во время операции блокировки каждый клиент может установить уникальное значение для переменной блокировки, и это уникальное значение можно использовать для идентификации текущего работающего клиента. При снятии блокировки клиент должен оценить, равно ли значение текущей переменной блокировки его собственному уникальному идентификатору, и только при их совпадении блокировка может быть снята, и проблема снятия блокировки по ошибке не возникнет.

В Redis как это реализовано?

2.4.3 Один узел гарантирует операцию атомарной блокировки
. Команда SETNX для пар ключ-значение, которые не существуют, сначала создаст, а затем установит значение (то есть «если оно не существует, установите его»), чтобы добиться того же эффекта, что и команда SETNX, Redis предоставляет аналогичную опцию NX для команды SET, которая используется для реализации «установить, если она не существует». Если используется опция NX, команда SET будет установлена ​​только в том случае, если пара ключ-значение не существует, в противном случае присвоение выполняться не будет. Кроме того, команду SET можно также выполнить с опцией EX или PX, чтобы установить время истечения срока действия пары ключ-значение.
Реализация кода блокировки
Например, при выполнении следующей команды SET создаст ключ и присвоит ключу значение только в том случае, если ключ не существует. Кроме того, время жизни ключа определяется значением опции секунды или миллисекунды.

set key value  [EX seconds | PX milliseconds] [NX]

С опциями NX и EX/PX команды SET мы можем использовать следующие команды для реализации операции блокировки.

//加锁,unique_value作为客户端唯一性的标识
SET lock_key unique_value NX PX1000a

● unique_value – это уникальный идентификатор клиента, который может быть представлен в виде случайно сгенерированной строки
● PX 10000 означает, что срок действия lock_key истечет через 10 с, чтобы клиент не работал ненормально и не мог снять блокировку в течение этого периода. .
Реализация кода снятия блокировки
Поскольку каждый клиент использует уникальный идентификатор в операции блокировки, поэтому при снятии операции блокировки необходимо оценить, равно ли значение переменной блокировки уникальному идентификатору клиента, выполняющего операцию снятия блокировки. следующим образом Показать:

//释放锁比较unique_value是否相等
if redis.call("get",KEYS[1]==ARGV[1] then)
	return redis.call("del",keys[1])
else
	return 0
end

Это псевдокод операции снятия блокировки, реализованный с помощью Lua-скрипта (unlock.script), где KEYS[1] представляет собой lock_key, ARGV[1] — уникальный идентификатор текущего клиента, оба значения при выполнении Lua script передается в качестве параметра.
Наконец, выполните следующую команду, чтобы завершить операцию снятия блокировки.

redis -cil --eval unlock.script lock_key,unique_value

Используйте сценарий Lua в операции освобождения блокировки —> это связано с тем, что логика операции освобождения блокировки также включает в себя несколько операций чтения переменной блокировки, оценки значения и удаления переменной блокировки, и когда Redis выполняет сценарий Lua, он может atomically Выполнить таким же образом, тем самым обеспечив атомарность операции снятия блокировки.

2.5 Недостатки:
используйте команды SET и сценарии Lua для реализации распределенных блокировок на отдельных узлах Redis. Используйте экземпляр Redis, чтобы сохранить переменную блокировки.Если экземпляр Redis выйдет из строя и выйдет из строя, переменная блокировки не будет иметь l. В это время клиент не может выполнять блокировочные операции, что повлияет на нормальное ведение бизнеса.При внедрении распределенных блокировок также необходимо обеспечить надежность блокировок

3. Реализуйте высоконадежную распределенную блокировку на основе нескольких узлов Redis.

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

3.1 Алгоритм распределенной блокировки Redlock
Алгоритм распределенной блокировки Redlock Цель:
во избежание проблемы, связанной с тем, что блокировка не может работать из-за сбоя экземпляра Redis, основная
идея алгоритма Redlock состоит в том,
чтобы позволить клиенту и нескольким независимым экземплярам Redis запрашивать блокировки по очереди.Если клиент Если клиент может успешно завершить операцию блокировки с более чем половиной экземпляров, клиент успешно получает распределенную блокировку, в противном случае блокировка не выполняется. Таким образом, даже в случае сбоя одного экземпляра Redis, поскольку переменная блокировки также сохраняется в других экземплярах, клиент по-прежнему может выполнять операции блокировки в обычном режиме, и переменная блокировки не будет потеряна.

Этапы выполнения алгоритма Redlock
Для реализации алгоритма Redlock требуется N независимых экземпляров Redis. Далее он делится на 3 этапа для завершения операции блокировки.

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

Операция блокировки здесь аналогична операции блокировки, выполняемой на одном экземпляре, используйте команду SET, укажите параметры NX, EX/PX и введите уникальный идентификатор клиента. Конечно, если экземпляр Redis выходит из строя, чтобы алгоритм Redlock мог продолжать работать в этом случае, необходимо установить период ожидания для операции блокировки.
Если клиенту не удается запросить блокировку экземпляра Redis до истечения времени ожидания, клиент продолжит запрашивать блокировку следующего экземпляра Redis. Время ожидания операции блокировки должно быть намного короче, чем эффективное время блокировки, которое обычно устанавливается в десятки миллисекунд.

Третий шаг заключается в том, что после того, как клиент завершит операцию блокировки со всеми экземплярами Redis, ему необходимо рассчитать общее время, затраченное на весь процесс блокировки.
Только при выполнении следующих двух условий клиент может считать блокировку успешной.
● Условие 1: клиент успешно получил блокировку более чем от половины (больше или равно N/2+1) экземпляров Redis ● Условие 2: общее время, затраченное
клиентом на получение блокировки, не превышает время действия блокировки.
После выполнения этих двух условий пересчитываем эффективное время блокировки и вычисляемый результат: начальное эффективное время блокировки — общее время, затраченное клиентом на получение блокировки.
● Если время действия блокировки слишком позднее для завершения операции с общими данными –> снимите блокировку, чтобы избежать ситуации, когда срок действия блокировки истечет до завершения операции с данными.
● Конечно, если клиент не выполняет эти два условия одновременно после выполнения операций блокировки со всеми экземплярами, клиент инициирует операцию по снятию блокировок со всех узлов Redis.
В алгоритме Redlock операция снятия блокировки такая же, как и операция снятия блокировки на одном экземпляре, если выполняется Lua-скрипт для снятия блокировки. Таким образом, пока более половины N экземпляров Redis могут нормально работать, нормальная работа распределенной блокировки может быть гарантирована.
Поэтому в реальных бизнес-приложениях надежность распределенных блокировок повышается за счет алгоритма Redlock.

4. Резюме:

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

  1. 1. Блокировка включает в себя три операции: чтение переменной блокировки, проверку значения переменной блокировки и установку значения переменной блокировки, но она должна выполняться в атомарной операции.Используйте команду SET с NX (установите, если она не существует) возможность добиться блокировки ;
  2. 2. Переменная блокировки должна установить время истечения срока действия, чтобы предотвратить получение клиентом исключения после получения блокировки, что приводит к невозможности снятия блокировки, добавьте параметр EX/PX (установить срок действия), когда команда SET выполняется и устанавливается время его истечения;
  3. 3. Значение переменной блокировки должно различать операции блокировки от разных клиентов, чтобы избежать случайных операций освобождения при снятии блокировки.При использовании команды SET для установки значения переменной блокировки значение, установленное каждый клиент является уникальным значением. Использование Hand определяет уникальное_значение клиента.
    Подобно блокировке, снятие блокировки также включает в себя три операции: чтение значения переменной блокировки, оценка значения переменной блокировки и удаление переменной блокировки, что невозможно реализовать одной командой, поэтому для выполнения блокировки используется сценарий Lua. операция выпуска. Атомарность операции снятия блокировки гарантируется атомарным выполнением скрипта Lua через Redis.
    Однако при реализации распределенных блокировок на основе одного экземпляра Redis экземпляр будет работать ненормально или выйдет из строя, что приведет к тому, что экземпляр не сможет выполнять операции блокировки.По этой причине Redis также предоставляет алгоритм Redlock для реализации распределения на основе нескольких instances Переменная блокировки поддерживается несколькими экземплярами.Даже если экземпляр выходит из строя, переменная блокировки все еще существует, и клиент все равно может завершить операцию блокировки. Алгоритм Redlock является эффективным решением для реализации высоконадежных распределенных блокировок.

Используйте команду SET с параметрами NX и EX/PX для выполнения операций блокировки Можно ли использовать следующие методы для реализации операций блокировки?

// 加锁
SETNX lock_key unique_value
EXPIRE lock_key 10S
// 业务逻辑
DO THINGS

Ответ: Если этот метод используется для реализации блокировки, хотя две команды SETNX и EXPIRE завершают атомарное суждение и установку значения переменной блокировки и операцию установки времени истечения срока действия переменной блокировки соответственно, когда эти две операции выполняются вместе , Атомарность не гарантируется. Если клиент выходит из строя после выполнения команды SETNX, но для переменной блокировки не задано время истечения срока действия, она не может быть освобождена на экземпляре, что приведет к тому, что другие клиенты не смогут выполнить операцию блокировки. Поэтому мы не можем использовать этот метод для блокировки.

Je suppose que tu aimes

Origine blog.csdn.net/qq_45656077/article/details/129796616
conseillé
Classement