Как создать 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-get install redis-server -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:7000
node-2:7000
node-3:7000
- Реплики:
node-1:7001
node-2:7001
node-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 value1
SET key2 value2
Синтаксис GET
:
GET key1
GET 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
ПОНРАВИЛАСЬ ИЛИ ОКАЗАЛАСЬ ПОЛЕЗНОЙ СТАТЬЯ, ПОДДЕРЖИ АВТОРА ДОНАТОМ
Обсуждение
Нет комментариев.