Играйте с кластером Redis Cluster

Redis
Играйте с кластером Redis Cluster

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

Redis Cluster децентрализован, что принципиально отличается от Codis, Redis Cluster разделен на 16384 слота, и каждый узел отвечает за часть данных. Информация о слоте хранится в каждом узле, и узел будет сохранять информацию о слоте в файле конфигурации, поэтому необходимо убедиться, что файл конфигурации доступен для записи. Когда клиент подключается, он получает информацию о слоте. Таким образом, когда клиенту необходимо получить доступ к определенному ключу, он может напрямую определить местонахождение узла на основе информации о слоте, кэшированной локально. Таким образом, будет несоответствие между информацией о слотах, кэшированной клиентом, и информацией о слотах сервера.Как решить эту проблему? Вот немного продаж сначала, и я объясню это позже.

характеристика

Во-первых, давайте взглянем на официальное введение в Redis Cluster.

  • High performance and linear scalability up to 1000 nodes. There are no proxies, asynchronous replication is used, and no merge operations are performed on values.
  • Acceptable degree of write safety: the system tries (in a best-effort way) to retain all the writes originating from clients connected with the majority of the master nodes. Usually there are small windows where acknowledged writes can be lost. Windows to lose acknowledged writes are larger when clients are in a minority partition.
  • Availability: Redis Cluster is able to survive partitions where the majority of the master nodes are reachable and there is at least one reachable slave for every master node that is no longer reachable. Moreover using replicas migration, masters no longer replicated by any slave will receive one from a master which is covered by multiple slaves.

Разве (кан) не хочет (бу) смотреть (дон)? Это не имеет значения, я разобью его и разобью, чтобы вы объяснили.

писать безопасно

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

Давайте сначала рассмотрим более распространенный случай потери записи:

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

Кроме того, есть еще одна ситуация.

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

Однако обычно этого не происходит, потому что, когда мастер теряет соединение достаточно долго, чтобы считаться отключенным, он начинает отклонять запросы на запись. Когда он восстановится, все еще будет короткий период времени, когда запрос на запись будет отклонен.Этот период времени предназначен для других узлов, чтобы обновить информацию о конфигурации в своей таблице маршрутизации.

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

Redis Cluster поддерживает переменную NODE_TIMEOUT.Если мастер возобновит соединение в течение времени NODE_TIMEOUT в приведенном выше случае, потери данных не будет.

Доступность

Если большинство мастеров кластера доступны, и у каждого недостижимого мастера есть хотя бы один ведомый, по истечении времени NODE_TIMEOUT начнется отработка отказа (обычно через 1–2 секунды), а кластер после отработки отказа все еще доступен.

Если в кластере есть N главных узлов с одним подчиненным, то при выходе из строя одного узла кластер должен быть доступен.Если два узла выйдут из строя, будет вероятность 1/(N*2-1) сделать кластер недоступным.

Чтобы повысить доступность, в Redis Cluster добавлена ​​новая функция, называемая миграцией реплик (миграция копий, ps: переведено мной).Эта функция фактически заключается в том, чтобы переставлять ведомые устройства кластера после каждого сбоя, и давать мастерам без ведомых устройств, оснащенных раб, чтобы лучше справиться с очередной неудачей.

представление

Redis Cluster не предоставляет прокси-сервер, а вместо этого позволяет клиентам перенаправляться непосредственно на нужный узел.

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

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

Для команд, которые работают с несколькими ключами, управляемые ключи должны находиться на одном узле, потому что данные не будут перемещаться. (если не перешарпировать)

Основная цель дизайна Redis Cluster — повысить производительность и масштабируемость, обеспечив лишь слабую безопасность и доступность данных (но разумную).

Модель назначения ключей

Кластер Redis разделен на 16384 слота. Это также означает, что в кластере может быть до 16 384 мастеров, но официальная рекомендация гласит, что максимальное количество мастеров равно 1000.

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

Redis Cluster будет использовать ключCRC16Алгоритм хеширует, а затем по модулю 16384 определяет слот, которому принадлежит ключ (хештеги нарушат это правило).

Keys hash tags

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

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

Сказав это, вы все еще можете быть сбиты с толку. Не волнуйся, давай поедим каштанов.

  1. Два ключа {Jackeyzhe}.following и {Jackeyzhe}.follower вычисляют хэш-значение Jackey.
  2. Ключ foo{{bar}} будет выполнять вычисление хэша на {bar
  3. follow{}{Jackey} будет оценивать всю строку

перенаправить

Когда мы говорили о производительности ранее, мы упомянули, что для повышения производительности Redis Cluster не предоставляет прокси, а использует перенаправление для подключения клиента к нужному узлу. Давайте подробно объясним, как Redis Cluster выполняет перенаправление.

ПЕРЕМЕЩЕНО перенаправление

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

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

GET x
-MOVED 3999 127.0.0.1:6381

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

Когда клиент получает ошибку MOVED, он может использовать команду CLUSTER NODES или CLUSTER SLOTS для обновления информации всего кластера, поскольку при перенаправлении редко происходит изменение одного слота, и обычно несколько слотов обновляются одновременно. Поэтому при получении ошибки MOVED клиент должен как можно раньше обновить информацию о распространении кластера. Когда кластер достигает стабильного состояния, соответствующая информация о слотах и ​​узлах, сохраненная клиентом, является правильной, и производительность кластера также достигает очень эффективного состояния.

В дополнение к перенаправлению MOVED полный кластер также должен поддерживать перенаправление ASK.

СПРОСИТЕ перенаправление

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

Миграция Redis Cluster основана на единицах слотов.Процесс миграции разделен на 3 шага (аналогично засовыванию слона в холодильник).Давайте возьмем каштан и посмотрим, какие шаги необходимы для переноса слота с узла A на узел B. :

  1. Сначала откройте дверь холодильника, то есть получите все списки ключей слота с узла А, а затем мигрируйте ключи один за другим. Перед этим слот узла А устанавливается в состояние миграции, а узел В узел установлен в слот импорта (оба используют команду CLUSTER SETSLOT).
  2. Второй шаг — поместить в него слона.Для каждого ключа используйте команду dump, чтобы сериализовать его на узле A, а затем выполнить команду restore на узле B через клиент, чтобы десериализовать его на узел B. .
  3. Третий шаг — закрыть дверь холодильника, то есть удалить соответствующий ключ из узла А.

Некоторые студенты спросят, а как насчет использования перенаправления ASK? То, что мы описали выше, — это только процесс миграции, во время которого Redis все еще необходимо предоставлять услуги внешнему миру. Только представьте, если в процессе миграции я прошу узел A запросить значение x, а A говорит: у меня его нет, я не знаю, было ли оно передано B или я его не сохранил, вы все равно сначала спросите Б. Затем он возвращает нам ошибку -ASK targetNodeAddr, давайте спросим B. В это время, если мы прямо спросим Б, Б обязательно прямо скажет: Это не в моей власти, ты должен спросить А. (-ПЕРЕМЕЩЕНО перенаправление). Поскольку в настоящее время миграция еще не завершена, B не ошибается, и x действительно не находится под его контролем в настоящее время. Но мы не можем позволить им пинать мяч туда-сюда, поэтому, прежде чем спрашивать B, мы сначала отправляем запрашивающую команду B и говорим B: я спрошу у вас значение ключа, вы должны относиться к нему как к своему собственному ключу. , вы не можете сказать нет знаний. Таким образом, если x был перенесен в B, результат будет возвращен непосредственно.Если B не может найти местонахождение x, это означает, что x не существует.

Отказоустойчивость

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

Сердцебиение и сплетни

Узлы в кластере будут хранить пакеты обмена Pong, и пакет Pong Pong имеет ту же структуру, но другой тип, и пакеты Ping Pong скреплены вместе, называемым пакетом Heartbeat.

Обычно узел отправляет пинг-пакет и получает понг-пакет, возвращенный получателем, но это не является абсолютным.Узел также может отправлять только понг-пакет, не позволяя получателю отправить ответный пакет.Эта операция обычно используется для передачи новой информации о конфигурации.

Узел будет отправлять определенное количество пакетов ping каждые несколько секунд. Если узел не получает пакет ping или pong от узла в течение более половины времени NODE_TIME, он отправит ping-пакет узлу до NODE_TIMEOUT. До NODE_TIMEOUT узел попытается переподключиться по протоколу TCP, чтобы избежать подключения по протоколу TCP. и ошибочно думают, что узел недоступен.

Содержимое пакета Heartbeat

Как мы уже говорили ранее, структура пакетов ping и pong одинакова, давайте подробно рассмотрим содержимое пакета.

Содержимое пакетов ping и pong можно разделить на две части: заголовок и сообщения сплетен, где заголовок содержит следующую информацию:

  • NODE ID — это 160-битная псевдослучайная строка, которая является уникальным идентификатором узла в кластере.
  • поля currentEpoch и configEpoch
  • флаг узла, который определяет, является ли узел ведущим или подчиненным, и есть некоторые другие флаги.
  • Битовая карта хеш-слота, который узел предоставляет услуги
  • TCP-порт отправителя
  • Воспринимаемое отправителем состояние кластера (не работает или нормально)
  • Если это ведомое устройство, оно содержит NODE ID ведущего.

Сплетни содержат то, что узел считает состоянием других узлов, но не всех узлов в кластере. В частности, следующая информация:

  • NODE ID
  • IP и порт узла
  • NODE flags

сплетни играют важную роль в обнаружении ошибок и обнаружении узлов.

Обнаружение ошибок

Обнаружение ошибок используется для определения того, находятся ли недостижимые узлы в кластере в автономном режиме, и если главный узел находится в автономном режиме, его подчиненный узел будет повышен до главного. Если его нельзя повысить, кластер остается в состоянии ошибки. В сводке значение флагов NODE включает в себя два вида PFAIL и FAIL.

PFAIL flag

Если узел обнаружит, что другой узел недоступен в течение времени, превышающего NODE_TIMEOUT, он пометит узел как PFAIL, то есть «Возможный сбой» (может быть в автономном режиме). Узел недоступен означает, что узел отправил пакет проверки связи, но не получил ответа после ожидания более NODE_TIMEOUT времени. Это также означает, что значение NODE_TIMEOUT должно быть больше, чем время, необходимое сетевому пакету для прохождения туда и обратно.

FAIL flag

Флаг PFAIL — это только локальная информация узла.Чтобы повысить статус ведомого до ведущего, необходимо обновить PFAIL до FAIL. Для обновления с PFAIL до FAIL должны быть выполнены некоторые условия:

  • Узел A помечает узел B как PFAIL
  • Узел A собирает статус узла B, идентифицированный большинством других мастер-узлов с помощью сообщений сплетен.
  • Большинство главных узлов находятся в периоде времени NODE_TIMEOUT * FAIL_REPORT_VALIDITY_MULT и идентифицируют узел B как PFAIL или FAIL.

Если вышеуказанные условия соблюдены, узел A идентифицирует узел B как FAIL и отправит сообщение узла B FAIL всем узлам. Узлы, получившие сообщение, также пометят B как FAIL.

Состояние FAIL является односторонним и может быть повышено только с PFAIL до FAIL, но не может быть понижено с FAIL до PFAIL. Однако есть несколько случаев, когда нужно очистить состояние FAIL:

  • Узел снова доступен и является ведомым узлом
  • Узел снова доступен и является главным узлом, но не предоставляет никаких слот-сервисов.
  • Узел снова доступен и является главным узлом, но ни один ведомый не был повышен до ведущего в течение длительного времени, чтобы заменить его.

Повышение PFAIL до FAIL использует слабый протокол:

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

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

строить

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

среда Redis

В первую очередь нам необходимо собрать необходимое нам окружение Redis.Здесь мы запускаем 6 инстансов Redis, номера портов 6379, 6380, 6479, 6480, 6579, 6580

Скопируйте 6 файлов конфигурации Redis и внесите следующие изменения (в качестве примера возьмем 6379, при необходимости измените номер порта и файл конфигурации):

port 6379
cluster-enabled yes
cluster-config-file nodes6379.conf
appendonly yes

Имя конфигурационного файла также необходимо изменить.После завершения модификации запустите 6 экземпляров соответственно (один из номеров портов на картинке неверен...).

Redis instances

Создать кластер Redis

После запуска экземпляра вы можете создать кластер Redis. Если версия Redis 3.x или 4.x, вам необходимо использовать инструмент под названием redis-trib.Для версий после Redis 5.0 команды Redis Cluster были интегрированы в редис-кли. Здесь я использую Redis5, поэтому нет отдельной установки инструмента redis-trib.

Далее выполнить команду

redis-cli --cluster create 127.0.0.1:6379 127.0.0.1:6380 127.0.0.1:6479 127.0.0.1:6480 127.0.0.1:6579 127.0.0.1:6580 --cluster-replicas 1

когда вы видите результат

[OK] All 16384 slots covered

Это означает, что кластер Redis успешно создан.

Просмотр информации об узле

На этом этапе мы можем использовать команду узлов кластера для просмотра информации об узле Redis Cluster.

cluster nodes

Видно, что три узла 6379, 6380 и 6479 сконфигурированы как главные узлы.

reshard

Далее пробуем операцию reshard

reshard_start

Как показано, введите команду

redis-cli --cluster reshard 127.0.0.1:6380

Redis Cluster спросит вас, сколько слотов нужно переместить, здесь мы перемещаем 1000, а затем он спросит вас, на какой узел переместиться, здесь мы вводим NODE ID 6479.

reshard_end

После завершения решарда вы можете ввести команду для просмотра состояния узла

redis-cli --cluster check 127.0.0.1:6480

Видно, что узел 6479 добавил 1000 слотов, то есть 0-498 и 5461-5961.

Добавить главный узел

add_node
Мы можем использовать команду add-node, чтобы добавить главный узел в кластер Redis.Мы видим, что мы добавили узлы 6679. После успешного добавления он не будет предоставлять услуги ни для одного слота.

Новый подчиненный узел

add_slave

Мы также можем использовать команду add-node для добавления подчиненного узла, но нам нужно добавить параметр --cluster-slave и использовать --cluster-master-id, чтобы указать, какому мастеру принадлежит новый подчиненный узел.

Суммировать

Наконец, подводя итог, введем

Особенности Redis Cluster: безопасность записи, доступность, производительность

Модель распределения ключей: используйте алгоритм CRC16, если вам нужно выделить один и тот же слот, вы можете использовать тег

Два перенаправления: MOVED и ASK

Толерантность к неисправностям: PFAIL и два состояния терпят неудачу

Наконец, я начал создавать экспериментальный кластер Redis.