Как создать Redis Cluster (Multi-Master)
Redis Cluster — это распределённая версия Redis, позволяющая автоматически шардировать данные и обеспечивать отказоустойчивость без единой точки отказа. В отличие от стандартного Redis, который работает как одиночный экземпляр, кластерная версия поддерживает горизонтальное масштабирование и репликацию.
Сценарий
Для обеспечения отказоустойчивости Redis Cluster требует как минимум 3 мастер-узла. При сбое одного из них кластер продолжит работу. Однако рекомендуемая конфигурация — 6 узлов: 3 мастера и 3 реплики, что повышает надежность и защищает от потери данных.
Рассматриваемая топология:
- Физические ноды — 3
node-1— 196.168.1.10node-2— 196.168.1.20node-3— 196.168.1.30
- Локальные экземпляры Redis на каждой ноде:
Master (порт 7000)— хранит данные и обрабатывает запросы.Replica (порт 7001)— дублирует мастер, используется для отказоустойчивости.
Схема:

Установка Redis (на всех узлах)
Для установки последней версии Redis, добавляем репозиторий в индекс APT, обновляем его и устанавливаем Redis на все узлы кластера:
apt-get install lsb-release curl gpg
curl -fsSL https://packages.redis.io/gpg | sudo gpg --dearmor -o /usr/share/keyrings/redis-archive-keyring.gpg
chmod 644 /usr/share/keyrings/redis-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/redis-archive-keyring.gpg] https://packages.redis.io/deb $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/redis.list
apt-get update
apt-get install redis -yПосле установки останавливаем службу Redis и отключаем ее из автозагрузки.
systemctl stop redis-server
systemctl disable redis-serverНастройка Redis (на всех узлах)
По умолчанию Redis использует один конфигурационный файл. Нам необходимо создать два файла – один для master, второй для replica. Создадим необходимые директории:
mkdir /etc/redis/cluster
mkdir /etc/redis/cluster/7000
mkdir /var/lib/redis/7000
mkdir /etc/redis/cluster/7001
mkdir /var/lib/redis/7001В конфигурациях Redis для мастер-узла и реплики я буду использовать для безопасности следующие параметры:
requirepass— задаёт пароль, который клиенты должны использовать для аутентификации при подключении к Redis-серверу.masterauth— задаёт пароль, который реплики используют для аутентификации при подключении к мастеру.
requirepass на мастере и masterauth на реплике должны совпадать, если на мастере включена аутентификация.cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 20 | head -n 1Создаем конфигурационный файл /etc/redis/cluster/7000/redis_7000.conf для мастер-узла со следующими параметрами:
port 7000
dir /var/lib/redis/7000/
appendonly no
protected-mode no
cluster-enabled yes
cluster-node-timeout 5000
cluster-config-file /etc/redis/cluster/7000/nodes_7000.conf
pidfile /var/run/redis/redis_7000.pid
logfile /var/log/redis/redis_7000.log
loglevel notice
requirepass [ПАРОЛЬ]
masterauth [ПАРОЛЬ]Аналогично создаем конфигурационный файл /etc/redis/cluster/7001/redis_7001.conf для реплики:
port 7001
dir /var/lib/redis/7001
appendonly no
protected-mode no
cluster-enabled yes
cluster-node-timeout 5000
cluster-config-file /etc/redis/cluster/7001/nodes_7001.conf
pidfile /var/run/redis/redis_7001.pid
logfile /var/log/redis/redis_7001.log
loglevel notice
requirepass [ПАРОЛЬ]
masterauth [ПАРОЛЬ]Затем устанавливаем соответствующие разрешения и права собственности на директории:
chown redis:redis -R /var/lib/redis
chmod 770 -R /var/lib/redis
chown redis:redis -R /etc/redisСоздание службы Redis (на всех узлах)
Создаем файл службы systemd для Redis на всех узлах. Сначала создаем файл службы для мастер-узла:
cat << EOF > /etc/systemd/system/redis_7000.service
[Unit]
Description=Redis database on 7000
After=network.target
[Service]
ExecStart=/usr/bin/redis-server /etc/redis/cluster/7000/redis_7000.conf --supervised systemd
ExecStop=/bin/redis-cli -h 127.0.0.1 -p 7000 shutdown
Type=notify
User=redis
Group=redis
RuntimeDirectory=redis
RuntimeDirectoryMode=0755
LimitNOFILE=65535
[Install]
WantedBy=multi-user.target
EOFЗатем для службы реплики:
cat << EOF > /etc/systemd/system/redis_7001.service
[Unit]
Description=Redis database on 7001
After=network.target
[Service]
ExecStart=/usr/bin/redis-server /etc/redis/cluster/7001/redis_7001.conf --supervised systemd
ExecStop=/bin/redis-cli -h 127.0.0.1 -p 7001 shutdown
Type=notify
User=redis
Group=redis
RuntimeDirectory=/etc/redis/cluster/7001
RuntimeDirectoryMode=0755
LimitNOFILE=65535
[Install]
WantedBy=multi-user.target
EOFПерезагружаем конфигурацию systemd, включаем автозапуск для обоих сервисов и запускаем их:
systemctl daemon-reload
systemctl enable redis_7000.service
systemctl enable redis_7001.service
systemctl start redis_7000.service
systemctl start redis_7001.serviceНастройка Redis Cluster
На каждой ноде теперь работают два экземпляра Redis.
- Мастера:
node-1:7000node-2:7000node-3:7000
- Реплики:
node-1:7001node-2:7001node-3:7001
На одном из серверов (например, node-1) выполним команду для создания кластера. Обратите внимание, что необходимо указать все 6 адресов:
redis-cli -c -h 196.168.1.10 -p 7000 -a [ПАРОЛЬ] --cluster create 196.168.1.10:7000 196.168.1.20:7000 196.168.1.30:7000 196.168.1.10:7001 196.168.1.20:7001 196.168.1.30:7001 --cluster-replicas 1Команда --cluster-replicas 1 сообщает, что каждому мастеру должна быть назначена одна реплика. При этом redis-cli самостоятельно распределит роли, сопоставив каждому мастеру реплику:
>>> Performing hash slots allocation on 6 nodes...
Master[0] -> Slots 0 - 5460
Master[1] -> Slots 5461 - 10922
Master[2] -> Slots 10923 - 16383
Adding replica 196.168.1.20:7001 to 196.168.1.10:7000
Adding replica 196.168.1.30:7001 to 196.168.1.20:7000
Adding replica 196.168.1.10:7001 to 196.168.1.30:7000
...Для проверки, что кластер успешно создался, войдем в систему на любом узле кластера Redis, используя следующую команду:
redis-cli -c -h <IP_НОДЫ> -p <PORT> -a [ПАРОЛЬ] CLUSTER NODESЕсли все узлы кластера в статусе — connected, то кластер собран и функционирует.
Проверка работоспособности кластера Redis
На этом этапе кластер настроен. Проверим поведение Redis кластера, для этого на разных нодах выполним команды SET и GET и посмотрим результат.
Синтаксис SET :
SET key1 value1SET key2 value2
Синтаксис GET :
GET key1GET key2
Подключится к Redis, можно с помощью следующей команды:
redis-cli -c -h <IP_НОДЫ> -p <PORT> -a [ПАРОЛЬ]Поочередно выполняю команды SET на разных мастер-узлах для проверки кластера.
196.168.1.10:7000> set a 1
-> Redirected to slot [15495] located at 196.168.1.30:7000
OK
196.168.1.30:7000> set b 2
-> Redirected to slot [3300] located at 196.168.1.10:7000
OK
196.168.1.10:7000> set c 3
-> Redirected to slot [7365] located at 196.168.1.20:7000
OK
196.168.1.20:7000> set d 4
-> Redirected to slot [11298] located at 196.168.1.30:7000
OKЗатем выполняю команды GET.
196.168.1.30:7000> get b
-> Redirected to slot [3300] located at 196.168.1.10:7000
«2»
196.168.1.10:7000> get a
-> Redirected to slot [15495] located at 196.168.1.30:7000
«1»
196.168.1.30:7000> get c
-> Redirected to slot [7365] located at 196.168.1.20:7000
«3»
196.168.1.20:7000> get d
-> Redirected to slot [11298] located at 196.168.1.30:7000
«4»Видим, что Redis отправляет ключи в правильные хэш-слоты на каждом сервере.
Проверка отказоустойчивости кластера Redis
В рамках рассматриваемой топологии, при отказе одного из серверов Redis кластер будет полностью работоспособен. Схема переключения в случае отказа одного мастер-узла будет выглядеть следующим образом:

Проведем тест отказоустойчивости, остановим процесс master на node-1 и проверим, повышает ли Redis кластер статус других серверов до master или нет.
Останавливаем узел master на node-1. Это должно заставить на node-2 узел replica 7001 взять на себя управление и изменить свою роль на master:
systemctl stop redis_7000.serviceТеперь войдем на node-2 и подключимся к процессу Redis replica.
redis-cli -c -h 196.168.1.20 -p 7001 -a [ПАРОЛЬ]Выполним следующую команду, чтобы увидеть, что процесс replica, запущенный на node-2, получил статус master.
196.168.1.20:7001> info
...
# Replication
role:masterМасштабирование кластера Redis
Добавление нового узла — это процесс добавления пустого узла, а затем переноса на него некоторых данных, если это новый мастер узел или указание на его настройку в качестве реплики известного узла, если это подчиненный узел.
Добавление нового узла в качестве мастер
Чтобы добавить новый мастер узел в существующий кластер, выполняем команду:
redis-cli -c -h <IP_НОВОЙ_НОДЫ> -p <PORT> -a [ПАРОЛЬ] --cluster add-node <IP_НОВОЙ_НОДЫ>:<PORT> <IP_ЛЮБОЙ_МАСТЕР_НОДЫ>:<PORT>Мы использовали --cluster add-node, где первым аргументом указан новый узел, а вторым — адрес любого мастера кластера. При успешном добавлении Redis подтвердит операцию:
...
[OK] New node added correctly.Перераспределяем ключевые слоты, чтобы новый мастер начал участвовать в хранении данных:
redis-cli -c -h <IP_ЛЮБОЙ_МАСТЕР_НОДЫ> -p <PORT> -a [ПАРОЛЬ] --cluster reshard <IP_НОВОЙ_НОДЫ>:<PORT>Redis предложит выбрать, сколько слотов перераспределять, откуда их забирать и как разнести.
16384 и количество уже имеющихся мастеров в кластере. Каждый из уже имеющихся мастеров отдаст часть своих слотов новому мастеру.После завершения слоты будут равномерно распределены, и новый мастер станет полноправным участником кластера.
Добавление нового узла в качестве реплики
Добавить новую реплику можно двумя способами. Первый способ, добавление аналогично добавлению мастер узла, но с использованием с параметра --cluster-slave и без указания к какому конкретно мастер узлу мы хотим добавить реплику:
redis-cli -c -h <IP_НОВОЙ_НОДЫ> -p <PORT> -a [ПАРОЛЬ] --cluster add-node <IP_НОВОЙ_НОДЫ>:<PORT> <IP_ЛЮБОЙ_МАСТЕР_НОДЫ>:<PORT> --cluster-slaveВ этом случае новый узел в качестве реплики будет добавлен для случайного мастер узла среди мастер узлов с меньшим количеством реплик.
Второй способ, мы можем указать, на какой именно мастер узел мы хотим нацелить новую реплику, с помощью следующей командной строки:
redis-cli -c -h <IP_НОВОЙ_НОДЫ> -p <PORT> -a [ПАРОЛЬ] --cluster add-node <IP_НОВОЙ_НОДЫ>:<PORT> <IP_ЛЮБОЙ_МАСТЕР_НОДЫ>:<PORT> --cluster-slave --cluster-master-id <ID_МАСТЕР_УЗЛА>Таким образом, мы назначаем новую реплику определенному мастер узлу.
Удаление узла из кластера Redis
Работающей ноды из кластера
Если удаляемый узел является мастером, то сперва необходимо перенести его хеш-слоты на другие узлы:
redis-cli -c -h <IP_НОДЫ> -p <PORT> -a [ПАРОЛЬ] --cluster reshard <IP_УДАЛЯЕМОГО_УЗЛА>:<PORT>В процессе ребалансировки система предложит указать:
- Количество слотов для переноса.
- ID исходного узла
- Куда необходимо перенести слоты.
Либо выполнить перенос слотов одной командой:
redis-cli -c -h <IP_НОДЫ> -p <ПОРТ> -a [ПАРОЛЬ] \
--cluster reshard <IP_УДАЛЯЕМОГО_УЗЛА>:<PORT> \
--cluster-from <ID_УДАЛЯЕМОГО_УЗЛА> \
--cluster-to <ID_УЗЛА_ПОЛУЧАТЕЛЯ> \
--cluster-slots <КОЛ-ВО СЛОТОВ> \
--cluster-yesЗдесь:
--cluster-from: ID исходного узла--cluster-to: ID целевого узла, на который будут перемещены слоты--cluster-slots: определяет сколько слотов нужно переместить--cluster-yes: автоматически подтверждает выполнение команды, без необходимости вводаyesвручную.
После того как все хеш-слоты перенесены, можно безопасно удалить узел. Используйте команду:
redis-cli -a [ПАРОЛЬ] --cluster del-node <IP_ЛЮБОЙ_УЗЕЛ>:<PORT> <ID_УДАЛЯЕМОГО_УЗЛА>После удаления узла снова проверьте состояние кластера:
redis-cli -c -h <IP_НОДЫ> -p <ПОРТ> -a [ПАРОЛЬ] CLUSTER NODESУбедитесь, что удаляемый узел больше не отображается в списке.
Недоступной ноды (аварийный случай)
Если нода не работает, её нельзя корректно вывести, но можно удалить принудительно.
redis-cli -h <IP_ЛЮБОЙ_РАБОТАЮЩЕЙ_НОДЫ> -p <PORT> cluster forget <ID_НЕДОСТУПНОЙ_НОДЫ>Если удалённый узел был мастером, а реплика не была автоматически повышена, нужно вручную перенести его слоты
redis-cli --cluster reshard <IP_ЛЮБОЙ_РАБОТАЮЩЕЙ_НОДЫ>:<PORT>- Указать количество слотов (если они зависли).
- Указать источник (
ID мёртвой ноды). - Указать новые узлы для назначения слотов.
Очистить конфигурацию на других нодах (если необходимо)
redis-cli -h <IP_ЛЮБОЙ_РАБОТАЮЩЕЙ_НОДЫ> -p <PORT> cluster resetПОНРАВИЛАСЬ ИЛИ ОКАЗАЛАСЬ ПОЛЕЗНОЙ СТАТЬЯ, ПОДДЕРЖИ АВТОРА ДОНАТОМ
Обсуждение
Нет комментариев.