Поделитесь опытом моих коллег-архитекторов NetEase по использованию Redis под весенней загрузкой~
Во-первых, в нем обобщается однопоточная рабочая модель сервера redis, четыре метода развертывания и сценарии использования redis, а затем с точки зрения исходного кода анализируются некоторые ямки использования redis в Springboot под клиентами jedis и lettuce, особенно в кластерный режим Проблема несовместимости!
Недавно скомпилированные обучающие видеоролики по архитектуре Java и базовые знания о проектах Dachang. Студенты, которые в них нуждаются, могут отправить мне личное сообщение и отправить их вам ~ Давайте учиться и развиваться вместе!
1 однопоточная модель сервера Redis
Redis использует внутренний обработчик файловых событий для обработки клиентских запросов.Обработчик файловых событий является однопоточным, поэтому Redis называется однопоточной моделью.
Структура обработчика файловых событий состоит из 4 частей: несколько сокетов, мультиплексор ввода-вывода, диспетчер файловых событий, обработчик событий (обработчик ответа на соединение, обработчик запроса на команду, обработчик ответа на команду).
Обработчик файловых событий использует механизм мультиплексирования ввода-вывода для одновременного мониторинга нескольких сокетов и выбирает соответствующий обработчик событий для обработки в соответствии с событиями на сокете.
Клиент Redis подключается к серверу reids через сокеты. Несколько сокетов могут одновременно генерировать разные операции, и каждая операция соответствует разным файловым событиям, но мультиплексор ввода-вывода будет прослушивать несколько сокетов и помещать события, сгенерированные сокетами, в очередь в очереди. , диспетчер событий извлекает событие из очереди за раз и передает событие соответствующему обработчику событий для обработки.
Причина, по которой однопоточная модель Redis также эффективна:
- чистая работа с памятью
- На основе неблокирующего механизма мультиплексирования ввода-вывода
- Один поток позволяет избежать частых проблем с переключением контекста нескольких потоков.
Почему Redis использует однопоточную модель?
Если принята многопоточная модель, процессор должен выполнять переключение контекста.Предполагая, что 1 МБ данных считывается 1000 раз несколькими потоками, тогда имеется 1000 переключений контекста, затем 1500 нс * 1000 = 1500 мкс, и однократно многопоточное чтение Для обработки 1 МБ данных требуется всего 250 мкс, поэтому нет необходимости использовать многопоточность вообще.
Когда уместно использовать многопоточное решение?
Для медленных устройств: дисковых, сетевых, SSD и т. д. запрос не привязан к потоку обработки, запрашивающий поток ставит запрос в бафф, после чего ждет заполнения баффа, а поток обработки обрабатывает баф . Потом бафф равномерно записывается на диск, либо читается с диска, что наиболее эффективно.
Является ли Redis потокобезопасным?
Redis фактически принимает концепцию закрытия потока, заключая задачи в поток, что естественным образом позволяет избежать проблем с безопасностью потоков, но для составных операций, которые должны полагаться на несколько операций Redis, по-прежнему требуются блокировки, и могут быть распределенные блокировки.
2 Метод развертывания Redis
2.1 Режим одного узла
Одноузловой режим имеет только один узел, который обычно используется для тестирования.
2.2 Режим ведущий-ведомый
Режим ведущий-ведомый включает в себя главный узел и несколько подчиненных узлов.Вообще говоря, главный узел используется для операций чтения и записи, а подчиненный узел — операции чтения пользователем.Данные главного узла могут быть синхронизированы с подчиненным узлом, поэтому даже если подчиненный узел поддерживает операции записи, он не работает.
2.3 Сторожевой режим
Режим Sentinel основан на режиме ведущий-ведомый.Sentinel отслеживает состояние узлов ведущий-ведомый для достижения высокой доступности в режиме ведущий-ведомый.Когда часовой обнаруживает, что главный узел не работает, часовой повторно выбирает ведущий из раб.
Вообще говоря, через кластер Sentinel можно управлять несколькими master-slave redis.Sentinel не следует развертывать на той же машине, что и Redis.В противном случае, после зависания сервера Redis, Sentinel также зависает. Использование дозорного кластера также необходимо для обеспечения высокой доступности Redis и предотвращения влияния на использование Redis после зависания дозорного узла.
При использовании режима Sentinel клиент не подключается к Redis напрямую, а подключается к IP-адресу и порту Sentinel.Sentinel предоставляет конкретную реализацию Redis, которая может предоставлять услуги, поэтому, когда главный узел зависает, Sentinel воспринимает и предоставляет новый главный узел для потребителей.
Режим Sentinel может в основном удовлетворить потребности общего производства и имеет высокую доступность. Однако, когда объем данных слишком велик для хранения на одном сервере, режим «ведущий-ведомый» или режим «дозорный» не могут удовлетворить спрос, поэтому сохраненные данные необходимо разбить на сегменты и хранить в нескольких экземплярах Redis.
2.4 Кластерный режим:
Появление кластера должно решить проблему ограниченной мощности Redis на одной машине и распределить данные Redis на несколько машин по определенным правилам.
Можно сказать, что кластер представляет собой комбинацию часового режима и режима ведущий-ведомый.Функции главного-ведомого и повторного выбора главного могут быть реализованы через кластер, поэтому, если вы настроите две реплики и три сегмента, вам потребуется шесть экземпляров Redis.
Как показано на рисунке, развернут кластер Redis с тремя ведущими и тремя подчиненными. Кластер Redis имеет фиксированные хеш-слоты 16384. Значение CRC16 вычисляется для каждого ключа, а затем по модулю 16384 для получения хеш-слота, соответствующего ключу. , Хранится в соответствующем слоте.
3 Springboot использует сводку Redis
spring-boot-starter-data-redis поддерживает два клиента Redis: jedis и lettuce
Клиентом по умолчанию, используемым Springboot 2.0, является lettuce. Lettuce используется в качестве клиента по умолчанию. Давайте отследим исходный код, чтобы проанализировать, как Springboot добавляется к клиенту lettuce. Сначала найдите связанный с Redis класс конфигурации загрузки RedisAutoConfiguration в пакете jar автоматически. загружается спрингбутом.
Здесь метод @Configuration @bean используется для внедрения RedisTemplate и StringRedisTemplate в контейнер. Метод внедрения обоих должен быть передан в RedisConnectionFactory. RedisConnectionFactory генерируется LettuceConnectionConfiguration, а JedisConnectionConfiguration импортируется @Import
Видно, что при отсутствии RedisConnectionFactory LettuceConnectionFactory по умолчанию будет внедряться в контейнер Spring.Если вы хотите использовать клиент jedis, вам нужно только вручную настроить JedisConnectionFactory и внедрить его в контейнер.
3.1 Разница между джедаями и салатом
- Jedis — это реализуемый сервер Redis с прямым подключением. Если он не является потокобезопасным в многопоточной среде, в настоящее время для добавления физических подключений к каждому экземпляру Jedis используется только пул соединений.
- Соединение Lettuce основано на Netty. К экземпляру соединения (StatefulRedisConnection) можно обращаться одновременно между несколькими потоками. StatefulRedisConnection является потокобезопасным, поэтому экземпляр соединения (StatefulRedisConnection) может удовлетворять одновременный доступ в многопоточной среде. Конечно, это также возможно.Масштабирование дизайна, если одного экземпляра подключения недостаточно, вы можете добавить экземпляры подключения по мере необходимости.
3.2 jedis анализ безопасности без потоков:
Проанализируйте процесс выполнения клиентом jedis каждой команды с точки зрения исходного кода.
Сначала выполните команду с помощью соответствующего метода класса Client
Затем выполнить с помощью метода sendCommand класса Connection
Метод connect вызывается каждый раз, когда выполняется метод sendCommand.
Как видно из метода подключения, сокет является общей переменной.Если два потока совместно используют экземпляр jedis, соединение сокета еще не установлено, и два потока входят, чтобы установить соединение сокета одновременно.
После того, как поток 1 установит сокетное соединение, он начнет получать входной и выходной потоки, в то же время поток 2 повторно инициализирует сокет и не выполняет установку сокетного соединения, в это время поток 1 не сможет получить входной и выходной потоки. входные и выходные потоки, потому что сокет в это время не подключен.
Jedis сам по себе не является многопоточным. Это не ошибка jedis, но дизайн jedis связан с тем, что сам redis является однопоточным. Абстракция экземпляров jedis связана с отправкой команд. Экземпляр jedis использует один поток и использует 100 потоков для отправки Существенной разницы между командами нет, поэтому нет необходимости делать их потокобезопасными. Но что, если вам нужно получить многопоточный доступ к серверу Redis? Затем используйте несколько экземпляров jedis, каждый поток соответствует экземпляру jedis, а не экземпляру jedis, совместно используемому несколькими потоками. Джедис связан с клиентом, что эквивалентно клиенту.Клиент наследует соединение, а соединение поддерживает соединение сокета.Для дорогостоящего соединения сокета оно обычно объединяется.Джедис предоставляет JedisPool.
3.3 Некоторые ямы, используемые джедаями и салатом в кластерном режиме
1. Главный узел Lettuce отключен в режиме кластера, а подчиненный узел обновлен до главного узла Как салат обновляет топологию кластера
Каждый узел в кластере отвечает только за часть слота, и слот может мигрировать с одного узла на другой, в результате чего клиент инициирует запрос к неправильному узлу. Следовательно, должен быть механизм для обнаружения и исправления, которым является перенаправление запроса.
Обновление топологии кластера выполняется в ClusterTopologyRefreshScheduler.Давайте перейдем к классу, чтобы узнать.
Класс ClusterTopologyRefreshScheduler реализует интерфейс ClusterEventListener для мониторинга событий кластера Redis, включая перенаправление запроса, перенаправление перемещения и повторное подключение.
В методе перенаправления сначала вызовите метод isEnabled, чтобы определить, следует ли включить обновление топологии кластера, а затем вызовите метод visibleTopologyRefreshSignal, чтобы обновить топологию кластера.
Чтобы определить, включена ли топология обновления кластера, в зависимости от того, содержит ли триггер адаптивного обновления в ClusterTopologyRefreshOptions указанный триггер перенаправления в конфигурации по умолчанию, как выглядит этот триггер?
Видно, что триггер для адаптивного обновления по умолчанию пуст, поэтому в режиме кластера, с использованием конфигурации салата по умолчанию, если мастер-нода выйдет из строя, топология кластера не будет обновлена, то есть соединение redis завершится ошибкой.
Адаптивное обновление топологии кластера можно включить в методе enableAllAdaptiveRefreshTriggers. Как обновить топологию кластера после включения адаптивного обновления?
Отправьте clusterTopologyRefreshTask, который обновляет топологию кластера в методе selectedTopologyRefreshSignal.
Вызовите метод reloadPartitions класса RedisClusterClient в задаче, чтобы перезагрузить информацию о топологии кластера для достижения эффекта обновления.
Помимо обновления топологии кластера путем запуска адаптивного обновления топологии кластера, вы также можете обновить топологию кластера, включив периодическое обновление.
После включения периодического обновления топологии кластера при инициализации топологии кластера будет вызываться активацияTopologyRefreshIfNeeded для запуска периодического обновления задачи топологии кластера.
Здесь будет принято решение о включении периодического обновления, и запланированная задача будет отправлена только после ее включения.
Сравнение периодического обновления и адаптивного обновления: существует два метода периодического обновления и адаптивного обновления. Лучше использовать адаптивное обновление, поскольку необходимо установить цикл периодического обновления. Если параметр слишком длинный, служба может быть недоступна. в течение определенного периода времени. Если параметр слишком короткий, ресурсы являются пустой тратой ресурсов, а адаптивное обновление обновляет топологию кластера на основе ответа сервера.
Нет необходимости включать оба метода обновления, и это также пустая трата ресурсов.
2. Яма, где клиент Jedis выполняет lua-скрипт
Преимущества Redis с использованием lua-скриптов:
- Уменьшите нагрузку на сеть. Несколько запросов могут быть отправлены в виде сценариев одновременно, чтобы уменьшить задержку в сети.
- Атомная операция. Redis выполнит весь скрипт как единое целое и не будет вставлен другими командами посередине. Таким образом, нет необходимости беспокоиться об условиях гонки во время написания сценариев и нет необходимости использовать транзакции.
- повторное использование. Сценарий, отправленный клиентом, постоянно хранится в Redis, поэтому другие клиенты могут повторно использовать сценарий без использования кода для выполнения той же логики.
Как клиент Jedis поддерживает сценарии lua?
Jedis выполняет сценарий lua через метод execute класса ScriptExecutor и далее вызывает метод eval в методе
Далее вызовите метод eval класса RedisScriptingCommands, поскольку клиент jedis используется в кластерном режиме, поэтому вызовите метод eval класса реализации JedisClusterScriptingCommands
Глядя на метод eval класса реализации JedisClusterScriptingCommands, сразу создается исключение, а сценарии не поддерживаются в режиме кластера.
Обходной путь заключается в использовании клиента салата, метод eval в классе LettuceScriptingCommands поддерживает сценарии.
Смотрите здесь маленьких друзей, если вам понравилась эта статья, не забудьтеВперед, в избранное, взаимодействие с помощью сообщений!
Если у вас есть какие-либо вопросы по статье, пожалуйста, свяжитесь со мной в области сообщений~
Я недавно собрал кое-что новоеДанные Java, в том числе личный обмен, пробные тестовые вопросы и видеогалантерея, если вам это нужно, пришлите мне личное сообщение!