Исходный код находится здесь:GitHub.com/Xbox1994/…
Введение
Распределенные блокировки очень распространены в распределенных системах.Например, при работе с общедоступными ресурсами, такими как продажа билетов, только один узел может продавать билеты на определенное место в каждый момент времени, например, чтобы избежать большого количества обращений запросов, вызванных проблема с инвалидацией кеша в базе данных
дизайн
Это очень похоже на вопрос на собеседовании: как реализовать распределенную блокировку? Во введении я в основном выдвинул некоторые требования к этому распределенному инструменту.Вы можете взглянуть на ответы ниже и подумать о том, как должны быть реализованы распределенные блокировки?
Прежде всего, нам нужна простая процедура ответа: анализ требований, проектирование системы, реализация и недостатки.
анализ спроса
- Может применяться в высокопараллельных распределенных системах
- Должны быть реализованы основные характеристики блокировок: после выделения блокировки другие узлы больше не могут получить доступ к ресурсам, находящимся под юрисдикцией блокировки; механизм отказа позволяет избежать бесконечных блокировок и взаимоблокировок.
- Лучше дополнительно реализовать расширенные функции блокировок и аналогичные функции инструментов параллелизма JUC: реентерабельный, блокирующий и неблокирующий, справедливый и нечестный, а также инструменты параллелизма JUC (Semaphore, CountDownLatch, CyclicBarrier).
Системный дизайн
Преобразование в дизайн является следующие требования:
- Процесс блокировки и разблокировки должен быть высокопроизводительным и атомарным.
- Операция состояния блокировки должна выполняться на общедоступной платформе, к которой может получить доступ распределенный узел.
Поэтому анализируем, что состав системы должен иметьмодуль хранения состояния блокировки,Модуль пула соединений для подключения модулей хранения,Блокировка внутреннего логического модуля
модуль хранения состояния блокировки
Существует три общих реализации распределенного хранилища блокировок, потому что эти условия для реализации блокировок могут быть выполнены: высокопроизводительная блокировка и разблокировка, атомарность операций и общедоступная платформа, к которой могут обращаться разные узлы в распределенной системе:
- База данных (используя уникальные правила первичного ключа, блокировки строк MySQL)
- Параметры NX и EX на основе Redis
- Временные упорядоченные узлы Zookeeper
Так как блокировка часто является инструментом распределенного управления, который используется только в случае высокого параллелизма, использование реализации базы данных вызовет определенную нагрузку на базу данных, и пул соединений будет заполнен, поэтому реализация базы данных не рекомендуется; мы Также необходимо поддерживать кластер Zookeeper, его сложнее реализовать. Если это не оригинальная система, она зависит от Zookeeper, и давление не слишком велико. Распределенные блокировки обычно не реализуются с помощью Zookeeper. Таким образом, для кешей довольно часто реализуются распределенные блокировки, потому чтоКэш относительно легкий, отклик кеша быстрый, пропускная способность высокая, а также имеется механизм автоматического аннулирования, гарантирующий снятие блокировки..
модуль пула соединений
Это может быть реализовано с помощью JedisPool.Если более поздняя производительность не будет хорошей, рассмотрите возможность реализации самостоятельно со ссылкой на HikariCP.
Блокировка внутреннего логического модуля
- Основные функции: блокировка, разблокировка, освобождение с течением времени
- Расширенные функции: реентерабельность, блокировка и неблокировка, честность и несправедливость, функции инструмента параллелизма JUC
Метод реализации
Модуль хранения использует Redis, а модуль пула соединений временно использует JedisPool.Внутренняя логика блокировки будет начинаться с основных функций и постепенно реализовывать расширенные функции.Ниже приведены конкретные идеи и коды для реализации различных функций.
Заблокировать, отпустить с течением времени
NX — это атомарная операция, предоставляемая Redis. Если указанный ключ существует, NX завершается сбоем. Если он не существует, операция set будет выполнена и вернет успех. Мы можем использовать это для реализации распределенной блокировки.Основная идея заключается в том, что успех набора означает, что блокировка получена, а отказ набора означает, что получение не удалось, и его необходимо повторить после сбоя. В сочетании с параметром EX ключ может быть автоматически удален по истечении тайм-аута.
Ниже приведена блокирующая операция блокирующей блокировки.Сняв цикл и вернув результат выполнения, можно записать неблокирующую блокировку (она не будет торчать):
Однако параметр тайм-аута вызовет проблему. Если тайм-аут превышен, но бизнес не был выполнен, это вызовет проблемы параллелизма, и другие процессы будут выполнять бизнес-код. Что касается того, как улучшить, мы поговорим об этом позже. .
разблокировать
Самый распространенный код разблокировки — использовать напрямуюjedis.del()
Метод удаляет блокировку Этот метод разблокировки блокировки без предварительного определения владельца блокировки заставит любого клиента разблокировать ее в любое время, даже если блокировка не является его собственной.
Например, может быть такая ситуация: клиент А блокируется, а клиент А через некоторое время разблокируется.Перед выполнением jedis.del() блокировка внезапно истекает.В это время клиент Б пытается успешно заблокироваться, а затем клиент А снова пытается заблокировать.Выполните метод del(), чтобы снять блокировку с клиента Б.
Так что нам нужен атомарный метод, чтобы разблокировать, и в то же время определить, является ли блокировка нашей собственной. Поскольку Lua-скрипты выполняются атомарно в Redis, их можно записать следующим образом:
воспользуемся тестовым шаттлом
На этом этапе мы можем написать тест, чтобы увидеть, сможем ли мы добиться желаемого эффекта.Приведенный выше код написан в RedisLock в папке src/main/java. Следующий тестовый код необходимо написать в src/test/java. тестирование только проверяет логику кода, оно не может проверить производительность после реального подключения к Redis, а также не может испытатьНапряженное и волнующее удовольствие от пребывания взаперти, поэтому этот проект в основном посвящен интеграционному тестированию. Если вы хотите попробовать модульное тестирование с помощью Mock, вы можете посмотретьэта статья.
Тогда интеграционный тест должен будет полагаться на экземпляр Redis. Чтобы избежать локальной установки Redis для запуска теста, я использовал встроенный инструмент Redis и следующий код, который поможет нам создать экземпляр Redis. Не стесняйтесь подключаться ~ Код можно посмотреть в классе EmbeddedRedis. Кроме того, Spring используется для интеграционного тестирования, не правда ли, более сердечно? Эквивалентно также предоставить пример интеграции Spring.
Тестировать качество кода под кодом, в котором нужно учитывать параллелизм, сложнее и труднее, потому что в тестовом примере будет использоваться многопоточная среда, которая может не пройти на 100% и ее сложно воспроизвести.Распределенные блокировки — относительно простая сценарий параллелизма, поэтому я стараюсь убедиться, что тесты имеют смысл.
Мой первый тестовый пример — проверить способность блокировки к взаимному исключению.После того, как A получает блокировку, B не может получить блокировку немедленно:
Но это только тестирует взаимное исключение операции блокировки, но не проверяет, будет ли разблокировка успешной и продолжится ли процесс, ожидавший блокировки, после разблокировки, так что вы можете видеть, как тестируется метод testLockAndUnlock. Не думайте, что писать тесты легко,Подумайте о различных ситуациях теста, разработайте тестовые сценарии и реализуйте их.Нелегко. Однако тесты, написанные в будущем, не будут представлены отдельно, ведь в этой статье мы хотим сосредоточиться на реализации распределенных блокировок.
Проблемы параллелизма, вызванные тайм-аутом выпуска
Проблема: если A устанавливает период тайм-аута после получения блокировки, но время выполнения бизнеса превышает период тайм-аута, A все еще выполняет бизнес, но блокировка была снята.В это время другие процессы получат блокировку и выполнят то же самое На данный момент распределенные блокировки бессмысленны из-за параллелизма.
Если вы говорите, что я могу судить о том, выполнена ли задача, когда срок действия ключа подходит к концу, а если нет, то автоматически продлевать время истечения, то проблема параллелизма действительно может быть решена, но срок ожидания не имеет смысла. установить тайм-аут Продолжительность времени для автоматического снятия блокировки по истечении времени ожидания, чтобы предотвратить блокировку других процессов. Поэтому я лично считаю, что лучшим решением будет уведомить сервер, чтобы он остановил задачу тайм-аута, когда истечет время блокировки, но это слишком тяжело для объединения механизма уведомления о сообщениях Redis; или позволить бизнес-коду проверить, истек ли тайм-аут. выполняется, но инструмент не работает. Это сделано для того, чтобы бизнес-внедрители уделяли больше внимания бизнесу?
Так что в этом вопросе реализация распределенных блокировок в Redis ненадежна.
Проблемы параллелизма, вызванные единственной точкой отказа
Установите архитектуру репликации master-slave, но некоторые данные будут потеряны перед синхронизацией из-за отказа главного узла, поэтому рекомендуетсяМногоуровневая архитектура, имеется N независимых мастер-серверов, и клиент отправит операцию получения блокировки на все серверы.
где оптимизация может продолжаться
- Реализуйте функции, подобные Semaphore, CountDownLatch, справедливой блокировке, несправедливой блокировке и блокировке чтения-записи в JUC, см.Внедрение Редиссона
- Обеспечьте конфигурацию с несколькими мастерами и реализацию блокировки и разблокировки
- Вместо этого используйте подписки для разблокировки сообщений с помощью семафора
Thread.sleep()
Чтобы не тратить время впустую, обратитесь к методу lockInterruptably RedissonLock в Redisson.
Ссылаться на
Исходный код Редиссона
Woohoo.Краткое описание.com/fear/from 2 не 4 ах ах 7 ах 1…
Сестра crossover.top/2018/03/29/…
Уууууу... Краткое описание.com/fear/'s 67 ах 50 патронов...
Блог Woohoo.cn на.com/Lin Jiqin/Afraid/…
вне никнейма
Недавно обобщил некоторые изJavaОчки знаний, связанные с интервью, заинтересованные друзья могут поддерживать их вместе ~
адрес:GitHub.com/Xbox1994/20…