SCROLL
Среднее время на прочтение: 5 мин.

Как создать Redis Cluster (Multi-Master)

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

Сценарий

Для обеспечения отказоустойчивости Redis Cluster требует как минимум 3 мастер-узла. При сбое одного из них кластер продолжит работу. Однако рекомендуемая конфигурация — 6 узлов: 3 мастера и 3 реплики, что повышает надежность и защищает от потери данных.

Рассматриваемая топология:
  • Физические ноды — 3
    • node-1 — 196.168.1.10
    • node-2 — 196.168.1.20
    • node-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 на реплике должны совпадать, если на мастере включена аутентификация.
В Linux среде можно сгенерировать рандомное значение, следующей командой — cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 20 | head -n 1

Создаем конфигурационный файл /etc/redis/cluster/7000/redis_7000.conf для мастер-узла со следующими параметрами:

/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 для реплики:

/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_УДАЛЯЕМОГО_УЗЛА>
Если удаляемый сервер также содержит реплику, сначала убедитесь, что она больше не используется. Если реплика была связана с удаляемым мастером, она автоматически станет «orphan» после удаления мастера.

После удаления узла снова проверьте состояние кластера:

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
 

ПОНРАВИЛАСЬ ИЛИ ОКАЗАЛАСЬ ПОЛЕЗНОЙ СТАТЬЯ, ПОДДЕРЖИ АВТОРА ДОНАТОМ

Обсуждение

0 комментариев

Нет комментариев.