Один Redis — это одна точка отказа. Пока сервер жив, всё отлично: кэш, очереди, сессии. В момент, когда он падает или заканчивается память, вместе с ним останавливается приложение — и вы узнаёте об этом от пользователей, а не от мониторинга.
Кластер Redis решает две задачи сразу: распределяет данные по нескольким серверам (потому что один сервер имеет конечную память) и продолжает работать при отказе узла (реплика автоматически становится мастером). Ниже — полный путь от выбора тарифов до проверенного failover, команды можно выполнять по порядку. Инструкция рассчитана на обычные VPS с Linux, без облачных сервисов и без внешних оркестраторов.

Схема размещения: три мастера и три реплики — шесть VPS в одной локации. Второй дата-центр на схеме — резервная площадка; она нужна, когда защищаться приходится не от отказа сервера, а от потери целого ДЦ.
Кому нужен кластер, а кому хватит одного сервера
Кластер — не «уровень повыше», а другая модель работы. Он стоит денег, серверов и внимания, поэтому сначала честно ответьте на два вопроса: сколько данных вы держите и что будет, если Redis выключится на час.
Хватит одного сервера, если:
- объём данных — единицы гигабайт, помещается в RAM одного VPS с запасом;
- простой в 10–30 минут приемлем (кэш, необязательные фоновые задачи);
- вы готовы перезапустить сервис руками.
Нужен кластер, если:
- данных больше, чем влезает в один разумный (по цене) VPS, или рост впереди;
- простой означает потерю денег или клиентов (корзины, платежи, очереди заданий);
- нужна запись, которая не останавливается при отказе одной машины.
Есть третий путь — managed-сервис. Облачный провайдер поднимает кластер за вас: в панели выбираете локацию, версию, конфигурацию ноды, количество реплик, политику вытеснения, пароль — и получаете готовый кластер с SLA. У Selectel, например, заявлена доступность записи 99,95% и чтения 99,99% для многонодного кластера. Платите за это существенно больше, чем за свой VPS, и теряете часть контроля: например, локацию и версию после создания не поменять. Ниже мы собираем свой кластер — это дешевле по железу и полностью под вашим управлением, но настраивать и обслуживать его придётся вам.
Три схемы отказоустойчивости: standalone, Sentinel, Cluster
Прежде чем идти в кластер, посмотрите на два более простых варианта — возможно, вам хватит их.
1. Standalone (обычный Redis). Один процесс, одна точка отказа. Резервная копия — только регулярные дампы. Когда данных больше, чем памяти, приходится идти в кластер.
2. Master + реплика + Sentinel. Один мастер на запись, одна или несколько реплик на чтение. Sentinels (минимум три процесса) следят за мастером и при его отказе назначают нового. Клиент спрашивает у Sentinel, где сейчас мастер. Это классическая схема «Redis для сервисов», и в реальных внедрениях её часто дополняют прокси — чтобы приложение обращалось к одному адресу и не знало про failover:
# sentinel.conf (на каждой из трёх машин)
sentinel monitor master01 10.0.0.11 6379 2
sentinel failover-timeout master01 6000
# haproxy: единая точка входа на порт 6379, трафик уходит текущему мастеру
listen redis
bind *:6379
option tcp-check
tcp-check send PING\r\n
tcp-check expect string +PONG
tcp-check send info\ replication\r\n
tcp-check expect string role:master
server redis1 10.0.0.11:6379 check inter 3s
server redis2 10.0.0.12:6379 check inter 3s
Схема отлично работает, но у неё есть предел: всё пишется на один узел, значит память ограничена одним сервером. И есть известная ловушка: если мастера перестают видеть друг друга (сеть), после истечения cluster-node-timeout реплика может стать мастером, а старый мастер — уйти в себя и «забыть» данные. Клиенты в это время могут писать в две разные копии. Sentinel снижает простой, но не увеличивает объём.
3. Redis Cluster. Данные разбиты на 16384 слота, которые распределяются между мастерами. Ключ всегда попадает к тому мастеру, который держит его слот. Минимум три мастера (иначе нет кворума для решения об отказе), у каждого — хотя бы одна реплика. Отказ мастера: реплика повышается автоматически, слоты переезжают к ней, кластер продолжает принимать записи.
Мастер A: слоты 0–5460 Реплика A' (копия A)
Мастер B: слоты 5461–10922 Реплика B' (копия B)
Мастер C: слоты 10923–16383 Реплика C' (копия C)
Итого: 16384 слота, 3 мастера, 3 реплики
Клиент обязан быть cluster-aware: он спрашивает карту слотов и сам ходит к нужному узлу. Если направить на кластер обычный клиент, он получит ответ вида MOVED 866 10.0.0.13:6379 — это не ошибка, а подсказка «этот ключ живёт в другом месте». Дальше мы всё это проверим руками.
Сколько серверов нужно и как выбрать тарифы
Минимум для прода: 6 серверов — три мастера и три реплики, по одной машине на процесс. Меньше нельзя: с тремя узлами (1 мастер + 2 реплики) вы теряете шардинг, а с одним мастером — саму идею отказоустойчивости.
Почему мастеров обычно три, а не один: кластер принимает решения голосованием мастеров, и для выбора нового мастера нужно большинство доступных мастеров с зачётными слотами. При трёх мастерах кластер выдерживает отказ одного из них: два оставшихся — это большинство, они поднимают реплики и продолжают работу. При двух мастерах отказ одного уже блокирует запись: кворума нет. Три мастера — это минимальная рабочая схема, а не универсальный оптимум: добавляя мастеров, вы одновременно повышаете требования к доступности кворума, зато распределяете нагрузку и память шире. Для больших объёмов имеет смысл 5–6 мастеров с репликами — считайте по памяти и по нагрузке.
Как считать память. Redis держит данные в RAM, плюс накладные расходы (служебные структуры, фрагментация, буферы репликации). Ориентир: нужный объём данных × 2 и не меньше 25–30% свободной памяти сверху. Хотите хранить 1 ГБ полезных данных на каждом мастере — берите VPS с 2 ГБ RAM. Кэш на 512 МБ — хватит 1 ГБ.
Пример: данные 1 ГБ на узел → нужен VPS с 2 ГБ RAM
Итого 6 серверов × 2 ГБ = 12 ГБ RAM в кластере (~6 ГБ полезных данных с репликами)
Эконом-вариант на старт: 3 VPS × 2 инстанса (6 процессов) — дешевле, но без защиты от падения машины
Эконом-вариант (три VPS, на каждом по два инстанса Redis — мастер и реплика чужого мастера) встречается в интернете часто и стоит вдвое дешевле. Он годится для тестов и небольших проектов, но надо понимать цену: падение одной машины уносит сразу два процесса — мастер и реплику. Кластер обычно это переживает (при --cluster-replicas 1 реплика второго уровня не поднимается автоматически), но запас прочности падает. Если выбираете этот путь — берите серверы с запасом по ядрам и памяти, потому что на одной машине будут жить два Redis.
Реплика не должна жить на том же физическом хосте, что мастер
Два VPS в одной локации у одного провайдера — это ещё не два независимых сервера. Технически они могут оказаться виртуалками на одном гипервизоре, на одном дисковом массиве или за одним сетевым устройством: тогда падение хоста уносит и мастера, и его реплику. Redis сам этого не видит — он считает узлы независимыми всегда, когда они отвечают по сети, и никаких меток «кто на каком железе» в кластере нет. Отдельный случай — rack-zone awareness: в Redis Enterprise он есть как настройка, в open-source Redis его нет, там распределением реплик управляете вы.
Проверить независимость заранее можно так:
# 1) Не на одном ли гипервизоре (косвенный признак — DMI/BIOS и серийники хоста)
sudo dmidecode -s system-product-name; sudo dmidecode -s system-uuid
cat /sys/class/dmi/id/product_uuid # у разных железных хостов значения разные
# 2) Не в одной ли подсети и не за одним ли шлюзом
ip -br addr; ip route get 8.8.8.8
# 3) Сравнить MAC-префиксы и трассу до мастеров
ip link | grep ether
traceroute -n 10.0.0.12
Соберите карту размещения и держите её рядом с кластером — при аварии она экономит часы:
Роль Узел Физический хост Локация Провайдер/гипервизор
Мастер A 10.0.0.11 (a1) hv-msk-07 Москва, ДЦ-1 провайдер №1
Реплика A 10.0.0.14 (a2) hv-msk-31 Москва, ДЦ-1 провайдер №1
Мастер B 10.0.0.12 (b1) hv-msk-12 Москва, ДЦ-1 провайдер №1
Реплика B 10.0.0.15 (b2) hv-nsk-04 Новосибирск провайдер №2
Мастер C 10.0.0.13 (c1) hv-nsk-02 Новосибирск провайдер №2
Реплика C 10.0.0.16 (c2) hv-nsk-11 Новосибирск провайдер №2
Если виртуалки попали на один хост, есть два пути: попросить у провайдера развести машины по разным гипервизорам (обычно это делается в момент создания VPS) либо вручную назначить реплику на узел из другой локации — репликация между ДЦ добавляет 1–5 мс задержки на запись в синхронном виде, но для асинхронной репликации Redis это допустимо. Переназначить реплику можно явно, не доверяя автоматике:
# взять id мастера и перевести нужную реплику под него
redis-cli -a 'Пароль' cluster nodes | grep master
redis-cli -a 'Пароль' --cluster add-node 10.0.0.15:6379 10.0.0.11:6379 --cluster-slave --cluster-master-id <id-мастера-B>
Под кластер берите одинаковые по ресурсам VPS в одной локации: одинаковая память (иначе данные распределятся неравномерно), одинаковый диск, минимальный сетевой пинг между серверами. На Tenku конфигурации с 2, 4, 8 и 12 ГБ RAM и NVMe — от 299 ₽/мес за 2 ГБ; конкретные цены и наличие локаций смотрите на странице тарифов, там данные подтягиваются из биллинга. Если планируете держать кластер и приложение на разных машинах, посмотрите статью о том, сколько ресурсов нужно и как не переплачивать.
Подготовка серверов
Ниже считаем, что у вас шесть серверов с Ubuntu 24.04 (Debian 12 — то же самое) и приватной сетью между ними. Адреса названы условно: 10.0.0.11…10.0.0.16. Первые три будут мастерами, вторые три — репликами; фактическое распределение сделает redis-cli при создании.
1. Первичная настройка на каждом сервере. Как зайти по SSH и что сделать в первые минуты — в отдельной статье первый вход на VPS. Базово:
# обновление и утилиты
apt update && apt upgrade -y
apt install -y curl gnupg lsb-release ufw
# часовой пояс и имя узла
timedatectl set-timezone Europe/Moscow
hostnamectl set-hostname redis-a1
# swap 1 ГБ — страховка от жёсткого OOM, для Redis это «на крайний случай»
fallocate -l 1G /swapfile && chmod 600 /swapfile && mkswap /swapfile && swapon /swapfile
echo '/swapfile none swap sw 0 0' >> /etc/fstab
2. Настройки ядра. Redis сам подсказывает их в логе при старте — сделаем заранее:
cat >> /etc/sysctl.conf <<'EOF'
vm.overcommit_memory = 1
net.core.somaxconn = 1024
EOF
sysctl -p
# отключаем Transparent Huge Pages (иначе растут задержки)
echo never > /sys/kernel/mm/transparent_hugepage/enabled
echo 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' >> /etc/rc.local
chmod +x /etc/rc.local
3. Файрвол. У Redis два порта на каждый инстанс: обычный (6379) и служебный кластерный шина-порт, порт + 10000 (16379). Кластерный порт забывают чаще всего, и тогда кластер молча не собирается: CLUSTER MEET уходит, ответа нет.
# на каждом узле — доступ к Redis только из приватной сети
ufw default deny incoming
ufw allow from 10.0.0.0/24 to any port 6379 proto tcp
ufw allow from 10.0.0.0/24 to any port 16379 proto tcp
ufw allow 22/tcp
ufw enable
Если серверы в разных сетях или у вас нет приватной сети — используйте публичные IP, но обязательно ограничьте доступ по IP-адресам остальных узлов и поставьте пароль (см. ниже). Открытый в интернет Redis без пароля живёт до первых сканеров: обычно это часы. Про базовые правила — в статье про безопасность VPS.
4. Имена узлов. Чтобы конфиги читались людьми, добавьте в /etc/hosts на каждом сервере строки вида:
10.0.0.11 redis-a1
10.0.0.12 redis-b1
10.0.0.13 redis-c1
10.0.0.14 redis-a2
10.0.0.15 redis-b2
10.0.0.16 redis-c2
Установка Redis
В Ubuntu 24.04 штатный пакет — ветка 7.0.x. Этого достаточно для кластера: redis-cli --cluster умеет всё, что нужно. Если хотите более свежую 7.4.x — подключайте официальный репозиторий Redis.
Вариант через штатный репозиторий (проще):
apt install -y redis-server
redis-server -v
systemctl stop redis-server # конфиг будем править до первого запуска
Вариант со свежей версией из официального репозитория:
curl -fsSL https://packages.redis.io/gpg | gpg --dearmor -o /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" > /etc/apt/sources.list.d/redis.list
apt update && apt install -y redis
Вариант со сборкой из исходников (если нужна конкретная версия или нестандартные модули). Так делали в старых руководствах, и он всё ещё рабочий:
apt install -y build-essential tcl pkg-config
cd /usr/local/src
curl -O https://download.redis.io/redis-stable.tar.gz
tar xzf redis-stable.tar.gz && cd redis-stable
make -j$(nproc) && make install
Конфигурация узла
Правим /etc/redis/redis.conf на каждом сервере. Ниже — минимальный рабочий набор для кластера. Комментарии в конфиге можно оставить как ориентир.
# слушаем приватный адрес узла, а не весь интернет
bind 10.0.0.11
protected-mode yes
port 6379
# кластер
cluster-enabled yes
cluster-config-file nodes-6379.conf
cluster-node-timeout 15000
cluster-replica-validity-factor 10
# FULL COVERAGE: если выставить no, кластер останется доступным даже при потере части слотов.
# Для продакшена с данными оставляйте yes — лучше остановиться, чем писать в неполный кластер.
cluster-require-full-coverage yes
# адрес, который узел сообщает другим узлам. Обязателен, если сервер за NAT/в облаке
# (иначе узлы увидят внутренний адрес контейнера и не смогут друг к другу подключиться)
# cluster-announce-ip 10.0.0.11
# пароль: защита и для клиентов, и для репликации (masterauth)
requirepass SlozhnyjParolIz30Simvolov
masterauth SlozhnyjParolIz30Simvolov
# данные: RDB + AOF (жёстче к диску, но переживает перезапуск без потерь)
appendonly yes
appendfsync everysec
save 900 1
save 300 10
# память: лимит и поведение при заполнении
maxmemory 1500mb
# для базы данных (нельзя терять ключи) — noeviction;
# для чистого кэша — allkeys-lru
maxmemory-policy noeviction
# логи
logfile /var/log/redis/redis-server.log
Три вещи, на которых спотыкаются чаще всего:
bindдолжен указывать на адрес, доступный другим узлам.bind 127.0.0.1— кластер никогда не соберётся.- пароль нужен и в
requirepass, и вmasterauth: без второго реплика не сможет синхронизироваться с защищённым мастером. maxmemoryставится ниже памяти сервера. Оставьте системе и буферам репликации 25–30%:maxmemoryдля VPS с 2 ГБ — около 1,5 ГБ.
Что именно гарантирует appendonly yes и appendfsync everysec. Эта связка защищает от потери данных при перезапуске процесса, но не даёт строгой гарантии сохранности последней записи: при everysec Redis сбрасывает AOF на диск раз в секунду, значит при аварии сервера теряется до ~1 секунды записей. Если запись подтверждена клиенту, но не легла ни в AOF, ни к реплике — она исчезнет. Вариант appendfsync always сбрасывает каждую запись, но заметно снижает пропускную способность и убивает задержки на медленных дисках. Практический вывод: AOF и репликация решают задачу доступности, а не сохранности — сохранность обеспечивают отдельные резервные копии, о которых речь ниже.
Запускаем и проверяем, что процесс поднялся в кластерном режиме:
systemctl enable redis-server && systemctl start redis-server
redis-cli -a 'SlozhnyjParolIz30Simvolov' info cluster | head -5
# cluster_enabled:1
# cluster_state:fail ← это нормально: узел ещё не в кластере
Безопасность для продакшена: TLS, ACL, приватная сеть
Пароль и ограничение по IP — это минимум, а не финиш. В продакшене к ним добавляют шифрование и разделение прав.
Приватная сеть обязательна. И клиентский порт, и cluster bus (6379 и 16379) не должны быть доступны из интернета. Если серверы в разных сетях — поднимайте приватную сеть или VPN между узлами (WireGuard, IPsec), а публичные адреса закрывайте полностью. Открытый кластерный порт — это не только чтение ваших данных: через него можно перевести узлы в нерабочее состояние.
TLS для клиентских соединений и для межузлового трафика. Начиная с Redis 6 есть TLS для клиентов, с 7.2 — шифрование и самого кластерного канала (tls-cluster yes). Настройка парная: на всех узлах должны быть сертификаты, подписанные одним ЦС, а имена в сертификатах — совпадать с именами, которые узлы сообщают друг другу.
# фрагмент redis.conf: TLS для клиентов и для cluster bus (Redis 7.2+)
port 0 # закрываем незашифрованный клиентский порт
tls-port 6379
tls-cert-file /etc/redis/tls/redis.crt
tls-key-file /etc/redis/tls/redis.key
tls-ca-cert-file /etc/redis/tls/ca.crt
tls-cluster yes # шифруем межузловой трафик (cluster bus — tls-port + 10000)
tls-replication yes
ACL вместо одного общего пароля. Redis 6+ умеет отдельных пользователей с ограничением команд и ключей — приложению незачем давать FLUSHALL и CONFIG:
redis-cli -a 'Пароль' ACL SETUSER app on '>парольПриложения' '~app:*' '+@read' '+@write' '+ping'
redis-cli -a 'Пароль' ACL SETUSER monitor on '>парольМонитора' '~*' '+@read' '+client|list' '+info'
redis-cli -a 'Пароль' ACL LIST
Секреты не передавайте через -a. Пароль в командной строке попадает в историю оболочки и в список процессов. Рабочие варианты: переменная REDISCLI_AUTH в защищённом окружении, файл ~/.rediscli с правами 600, менеджер секретов, а в конфигах — include отдельного файла с паролем, доступным только владельцу:
chmod 600 /etc/redis/redis.conf
printf 'export REDISCLI_AUTH=%s\n' "$(grep -oP '(?<=^requirepass ).*' /etc/redis/redis.conf)" > /root/.redis_auth
chmod 600 /root/.redis_auth && . /root/.redis_auth # дальше: redis-cli без -a
Создание кластера
Когда на всех шести серверах запущены узлы с cluster-enabled yes, собираем кластер одной командой. Порядок адресов важен: первые три станут мастерами, следующие три — их репликами.
redis-cli --cluster create \
10.0.0.11:6379 10.0.0.12:6379 10.0.0.13:6379 \
10.0.0.14:6379 10.0.0.15:6379 10.0.0.16:6379 \
--cluster-replicas 1 -a 'SlozhnyjParolIz30Simvolov' --cluster-yes
Утилита предложит план распределения слотов и попросит подтверждение (флаг --cluster-yes отвечает согласием автоматически). Ожидаемый результат — строки про три мастера с диапазонами слотов и завершение вида All 16384 slots covered.
Проверяем состояние и карту:
redis-cli -a 'SlozhnyjParolIz30Simvolov' cluster info | grep -E 'cluster_state|cluster_slots_assigned|cluster_known_nodes'
# cluster_state:ok
# cluster_slots_assigned:16384
# cluster_known_nodes:6
redis-cli -a 'SlozhnyjParolIz30Simvolov' cluster nodes
# 8f2b… 10.0.0.11:6379@16379 myself,master - 0 0 1 connected 0-5460
# 3c91… 10.0.0.12:6379@16379 master - 0 0 2 connected 5461-10922
# a4d7… 10.0.0.13:6379@16379 master - 0 0 3 connected 10923-16383
# b1e0… 10.0.0.14:6379@16379 slave 8f2b… 0 0 4 connected
# …
# расширенная проверка (отвечает на вопрос «всё ли консистентно»)
redis-cli --cluster check 10.0.0.11:6379 -a 'SlozhnyjParolIz30Simvolov'
Если вместо cluster_state:ok вы видите fail и cluster_slots_assigned:0 — смотрите раздел «Типичные ошибки»: почти всегда это закрытый кластерный порт 16379 или bind не на тот адрес.
Проверка, что кластер жив
Клиентский доступ к кластеру всегда идёт с флагом -c: он включает переадресацию по слотам.
redis-cli -c -h 10.0.0.11 -p 6379 -a 'SlozhnyjParolIz30Simvolov'
127.0.0.1:6379> SET user:1001 "ok"
→ Redirected to 10.0.0.12:6379
127.0.0.1:6379> GET user:1001
"ok"
Полезные команды для отладки:
# в какой слот попадёт ключ и кто его держит
redis-cli -a 'Пароль' CLUSTER KEYSLOT user:1001
# современная карта слотов и шардов (Redis 7+), покажет владельца и реплики
redis-cli -a 'Пароль' CLUSTER SHARDS
# распределение ключей по узлам
redis-cli --cluster info 10.0.0.11:6379 -a 'Пароль'
Ответ MOVED 12345 10.0.0.13:6379 означает, что ключ принадлежит другому слоту — это нормальная работа кластера, а не ошибка. Ответ ASK встречается во время миграции слотов: клиент должен отправить команду целевому узлу. Все cluster-aware драйверы (redis-py, ioredis, predis, Lettuce, go-redis) умеют это сами — важно, чтобы клиент был кластерный, а не обычный:
# Python: кластерный клиент (не обычный Redis!)
from redis.cluster import RedisCluster
rc = RedisCluster(host='10.0.0.11', port=6379, password='Пароль', decode_responses=True)
Замеры: задержки, нагрузка и поведение при отказе
«Работает» и «быстро работает» — разные утверждения. Перед продом снимите три группы цифр: сетевую задержку до узлов, пропускную способность под нагрузкой и поведение при отказе.
# сетевая задержка до конкретного узла (измеряется RTT запросов, не один пинг)
redis-cli -h 10.0.0.12 -p 6379 -a 'Пароль' --latency
redis-cli -h 10.0.0.12 -p 6379 -a 'Пароль' --latency-history -i 5
# локальная задержка САМОГО redis на узле: это тест CPU/ядра, а не сети.
# Делайте его на узле, без нагрузки: сравнивайте узлы между собой
redis-cli --intrinsic-latency 100
Показательна разница между двумя последними командами: если --latency до узла в одном ДЦ десятки микросекунд, а --intrinsic-latency показывает миллисекунды — сервер тормозит сам (перегрузка CPU, медленный диск под AOF, своп), а не сеть.
Нагрузочный тест запускайте с отдельной машины, а не внутри кластера, и обязательно cluster-aware клиентом — redis-benchmark в режиме кластера умеет обходить узлы:
redis-benchmark -h 10.0.0.11 -p 6379 -a 'Пароль' --cluster -t set,get -n 200000 -c 50 -d 100 --latency
Что сравнивать до и после изменений:
- p50, p95, p99 задержки, а не среднее: среднее скрывает «хвосты», а приложение страдает именно от них;
- пропускную способность (ops/sec) на мастеров отдельно — если один узел из трёх даёт половину общей нагрузки, слоты разложены неровно;
- поведение при отказе: остановите мастера под нагрузкой и замерьте, сколько запросов упало и за сколько секунд клиент пошёл на новый узел. Это и есть ваш реальный RTO.
Клиент в кластере: MOVED, ASK, повторы и hash tags
Кластер меняет не только инфраструктуру, но и поведение приложения. Минимум, который нужно предусмотреть в коде.
MOVED и ASK — это не ошибки, а команды «сходи в другое место». Клиент должен уметь их обрабатывать и обновлять карту слотов. Всё, что нужно сделать приложению, — использовать кластерный драйвер (RedisCluster в redis-py, Cluster в ioredis, Predis\Cluster в PHP, Lettuce/go-redis в JVM и Go).
MOVED 5461 10.0.0.12:6379 ключ принадлежит другому слоту — обновить карту и повторить там
ASK 5461 10.0.0.12:6379 слот сейчас переезжает — выполнить один запрос на целевом узле
CLUSTERDOWN нет кворума или потеряны слоты — это уже авария, ретраи не помогут
Повторы записи должны быть идемпотентными. В момент failover клиент получает таймаут и не знает, применилась ли команда. Если это INCR счётчика баланса или списание — слепой повтор спишет дважды. Правильные подходы: идемпотентные операции, ключ-маркер (SETNX lock:op:<id>), версионирование, или перенос неидемпотентных действий в очередь с дедупликацией. Ограничьте число повторов (2–3) и добавьте паузу с ростом — иначе после восстановления узла вы получите шквал запросов.
Hash tags решают проблему мультиключевых операций. Ключи в кластере распределяются по слотам через CRC16, поэтому MGET user:1 user:2 может попасть в разные слоты и упасть с CROSSSLOT. Если ключи должны лежать рядом — задайте общий тег в фигурных скобках:
user:{42}:profile и user:{42}:settings → один слот (тег «42»), работают транзакции и Lua
user:42:profile и user:43:profile → разные слоты (для MSET/MGET вместе не годятся)
Правила, о которых лучше знать заранее: мультиключевые команды (MSET, MGET, SUNIONSTORE, PFCOUNT) работают только с ключами одного слота; SELECT в кластере не поддерживается — используйте отдельную нумерацию БД на уровне префиксов; Lua-скрипты обязаны обращаться только к ключам одного слота; KEYS на проде — плохая идея в любом Redis, а в кластере вы получите ещё и результат только одного узла.
Failover: проверяем отказ мастера
Это тест, который обязательно нужно провести до продакшена. Останавливаем Redis на одном мастере и смотрим, как кластер поднимет его реплику:
# на мастере A (10.0.0.11)
systemctl stop redis-server
# следим с любого другого узла
watch -n 2 "redis-cli -a 'Пароль' cluster nodes | grep master"
# ожидаемо: через cluster-node-timeout (15 с) плюс время выборов реплика A'
# (10.0.0.14) становится master, а старая строка получает флаг fail
Проверяем, что данные не потерялись и запись идёт:
redis-cli -c -h 10.0.0.12 -p 6379 -a 'Пароль' GET user:1001
redis-cli -c -h 10.0.0.12 -p 6379 -a 'Пароль' SET user:1002 "after-failover"
Возвращаем узел в строй — он вернётся уже репликой и синхронизируется автоматически:
systemctl start redis-server # на 10.0.0.11
redis-cli -a 'Пароль' cluster nodes | grep 10.0.0.11
# 10.0.0.11:6379 … slave <id> … — узел снова в кластере, но уже как реплика
Замерьте фактическое время переключения у себя: в него входят cluster-node-timeout, время выборов и время, за которое приложение переподключится. Если приложение живёт без ретраев, для него 15–20 секунд недоступности записи — это авария, поэтому retry-логика в клиенте обязательна.
Отдельно про потери при переключении. Репликация в Redis асинхронная: мастер отвечает клиенту, не дожидаясь подтверждения от реплики. Если мастер упал, часть подтверждённых записей могла не дойти до реплики — они потеряются при повышении. Команда WAIT заставляет мастера дождаться подтверждения от реплик, но она не превращает репликацию в синхронную и не отменяет потерю при падении мастера после её завершения. Поэтому в схеме «Redis как единственное хранилище» проверяйте не только факт failover, но и объём потерянных записей в тесте: остановите мастера под нагрузкой и посчитайте, сколько подтверждённых операций не дожило до нового мастера.
Эксплуатация: рост, обновления, замена узлов
Добавить новый узел. Сначала запускаем Redis на новом сервере с тем же конфигом, потом добавляем в кластер:
redis-cli --cluster add-node 10.0.0.17:6379 10.0.0.11:6379 -a 'Пароль' # как мастер
redis-cli --cluster add-node 10.0.0.18:6379 10.0.0.11:6379 --cluster-slave -a 'Пароль' # как реплика
Новый мастер получит ноль слотов — пока в него не переедут ключи, он ничего не хранит. Перераспределяем:
redis-cli --cluster reshard 10.0.0.11:6379 -a 'Пароль' # интерактивно: сколько слотов, куда
redis-cli --cluster rebalance 10.0.0.11:6379 -a 'Пароль' # автоматически разложить слоты равномерно
Вывести узел. Сначала освобождаем слоты (если это мастер), затем удаляем:
redis-cli --cluster reshard 10.0.0.11:6379 --cluster-from <id-выводимого> --cluster-to <id-принимающего> --cluster-slots <N> -a 'Пароль' --cluster-yes
redis-cli --cluster del-node 10.0.0.11:6379 <id-узла> -a 'Пароль'
Обновить версию без простоя. Реплики обновляются по одной, затем мастера — по одному, с ручным переводом мастера на его реплику:
# на одном мастере: аккуратно понижаем узел в реплику и обновляем его парой
redis-cli --cluster check 10.0.0.11:6379 -a 'Пароль' # перед каждым шагом
# после переключения мастера обновляйте освободившийся узел
Правило простое: никогда не обновляйте больше одного узла одновременно и не трогайте nodes-6379.conf руками — этот файл ведёт сам Redis, ручная правка ломает идентификаторы узлов.
Бэкапы: реплика — это не бэкап
Реплика защищает от отказа железа, но не от ошибки в приложении, которая удалила половину ключей: изменение мгновенно размножится на все копии. Поэтому бэкап — это снимок, вынесенный на другую машину, и проверенное восстановление.
# снимок RDB на каждом мастере
redis-cli -a 'Пароль' BGSAVE
redis-cli -a 'Пароль' INFO persistence | grep rdb_last_bgsave_status # ok
# копируем дамп на отдельный сервер (не в тот же дата-центр, если есть возможность)
rsync -avz -e ssh /var/lib/redis/dump.rdb backup@backup-host:/srv/redis-$(date +%F)-a1.rdb
Что учесть:
- AOF (
appendonly yes) даёт более точное восстановление, но занимает больше диска — следите за размером и делайтеBGREWRITEAOF; - храните дампы всех мастеров, иначе восстановите только часть слотов;
- раз в месяц проверяйте восстановление на отдельной машине: поднять Redis, положить дамп, запустить, сравнить количество ключей (
DBSIZE,INFO keyspace). Бэкап без проверки — это надежда, а не бэкап. Подробнее — в статье бэкапы VPS.
Восстановление после потери узла или целого ДЦ: RPO и RTO
Перед аварией стоит письменно ответить на два вопроса: RPO — сколько данных вы согласны потерять (в минутах или операциях) и RTO — за сколько времени обязаны поднять сервис. От этих цифр зависит вся схема: частота дампов, наличие второго ДЦ, наличие дежурного.
Сценарий 1: упал один узел. Ничего не делаем вручную: реплика станет мастером, кластер продолжит работу. Задача — вернуть узел и убедиться, что он подключился репликой:
redis-cli -a 'Пароль' cluster nodes # узел должен быть slave и connected
redis-cli -a 'Пароль' --cluster check 10.0.0.11:6379
Сценарий 2: потеряны все узлы или всё ДЦ. Здесь нужен бэкап и план. Порядок действий:
# 1) убедиться, что бэкап целый и свежий (дата, размер, контрольная сумма)
ls -la /srv/redis-2026-10-16-*.rdb && sha256sum /srv/redis-2026-10-16-a*.rdb
# 2) поднять новый Redis на чистых серверах с тем же redis.conf (cluster-enabled yes)
# 3) раздать дампы: для каждого будущего мастера — его собственный dump.rdb в каталог данных
# 4) запустить узлы, затем собрать кластер заново с ТОЙ ЖЕ раскладкой слотов
redis-cli --cluster create 10.0.0.11:6379 10.0.0.12:6379 10.0.0.13:6379 \
10.0.0.14:6379 10.0.0.15:6379 10.0.0.16:6379 --cluster-replicas 1 --cluster-yes -a 'Пароль'
# 5) проверить полноту данных
redis-cli -a 'Пароль' --cluster info 10.0.0.11:6379
redis-cli -a 'Пароль' INFO keyspace
Важные предупреждения по этому сценарию:
- слоты нужно раздавать тем же мастерам, что и раньше, иначе часть данных окажется «не на своём» узле и кластер её не увидит;
- RPO напрямую зависит от частоты дампов: ежедневный бэкап означает потерю до суток данных; для RPO в часы нужны копии каждые 1–6 часов;
- реплика в том же ДЦ не спасает от потери ДЦ: нужен либо второй ДЦ, либо вынос дампов в другое место;
- проверьте восстановление заранее на тестовом кластере: первое восстановление в момент аварии почти всегда идёт с ошибками.
Мониторинг: минимум, который спасает
Мониторить нужно не «сервер в целом», а состояние кластера. Соберите метрики:
redis-cli -a 'Пароль' info cluster | grep -E 'cluster_state|cluster_slots_fail|cluster_known_nodes'
redis-cli -a 'Пароль' info memory | grep -E 'used_memory_human|maxmemory_human|mem_fragmentation_ratio'
redis-cli -a 'Пароль' info stats | grep -E 'evicted_keys|rejected_connections|keyspace_hits'
redis-cli -a 'Пароль' slowlog get 10
На что ставить алерты в первую очередь:
cluster_state!=ok— авария, будите дежурного;cluster_slots_fail> 0 — потеряны слоты, часть данных недоступна;evicted_keysрастёт (для кэша) — мало памяти, нужно расширять кластер;rejected_connections> 0 — закончились файловые дескрипторы/память;master_link_status:downна реплике — репликация сломалась;- размер AOF и свободное место на диске — заполненный диск останавливает запись.
Для графиков подойдёт любой exporter (redis_exporter + Prometheus + Grafana) или даже простой скрипт по cron, который раз в минуту снимает INFO и отправляет в ваш мониторинг. Про общую диагностику «тормозит сервер» — в статье почему VPS тормозит.
Полный набор метрик и алерты
Одного cluster_state:ok мало: кластер может быть «здоров», пока реплика молча отстаёт на час, а диск заполнен под AOF. Снимайте метрики по каждой группе и ставьте пороги:
redis-cli -a 'Пароль' INFO memory | grep -E 'used_memory:|maxmemory:|mem_fragmentation_ratio|maxmemory_policy'
redis-cli -a 'Пароль' INFO stats | grep -E 'evicted_keys|rejected_connections|keyspace_hits|keyspace_misses'
redis-cli -a 'Пароль' INFO persistence | grep -E 'aof_enabled|aof_last_write_status|aof_current_size|rdb_last_bgsave_status'
redis-cli -a 'Пароль' INFO replication | grep -E 'role|master_link_status|master_last_io_seconds_ago|slave_repl_offset'
redis-cli -a 'Пароль' INFO replication | grep -E 'lag|offset' # на реплике: отставание в секундах
Минимум, который стоит повесить на алерты:
- отставшая реплика:
master_link_status:downилиmaster_last_io_seconds_agoбольше нормы (например, 10 с) — при аварии такая реплика не станет мастером без потери данных; - разъезд данных: сравните
master_repl_offsetмастера и реплики — растущая разница означает, что вы копите будущую потерю; - память:
used_memoryподходит к 80–85%maxmemory,mem_fragmentation_ratioустойчиво выше 1,5 — пора расширять кластер или чистить; - вытеснение и отказы:
evicted_keysрастёт (для БД это потеря данных),rejected_connectionsбольше нуля; - диск и AOF: свободное место и
aof_last_write_status:ok— на заполненном диске Redis перестаёт писать; - кворум: число живых мастеров упало ниже половины,
cluster_slots_failбольше нуля; - деградация задержек: p99 из
--latencyили из метрик приложения выше привычного в 2 раза.
Дополнительно полезно логировать SLOWLOG (медленные команды) и следить за свопом: Redis, ушедший в swap, перестаёт держать обещанные микросекунды.
Типичные ошибки и как их не допустить
cluster_state:fail, слотов 0. Не открыт кластерный порт (6379 + 10000 = 16379) илиbindсмотрит на127.0.0.1. Проверьтеss -tlnp | grep 6379и правила файрвола.CLUSTER MEETне срабатывает. Между узлами нет связи: разные подсети, NAT безcluster-announce-ip, блокировка по MTU. Проверьтеredis-cli -h <другой узел> pingс каждого сервера.- Кластер не создаётся: «Not all 16384 slots covered». Один из мастеров не поднялся или вы указали адреса, до которых утилита не дотягивается.
- Реплика не синхронизируется. На мастере задан
requirepass, а на реплике нетmasterauth(или пароли разные). - Клиент ловит MOVED. Подключились обычным клиентом вместо кластерного или забыли флаг
-cвredis-cli. - Ошибки записи после роста данных. Кончилась память и
maxmemory-policy noevictionзапрещает вытеснение: расширяйте кластер или меняйте политику для кэша. - Данные стали недоступны после падения машины. Кластер собран «в один сервер по два инстанса» — падение унесло и мастера, и реплику.
cluster-node-timeoutслишком маленький. При сетевых икотах кластер начинает «моргать»: реплики бесконечно перевыбирают мастеров. Для продакшена 15 000 мс — разумный минимум.- Файл
nodes.confправили руками. Узлы путают идентификаторы. Правильный путь —redis-cli --cluster fix. - Пароль в командной строке. Он попадает в историю оболочки. Или настройте переменную
REDISCLI_AUTHв окружении, или используйте--askpass, или ACL-пользователей вместо общего пароля.
Чек-лист перед продом
- Кластер собран из трёх мастеров и трёх реплик,
cluster_state:ok, покрыты все 16384 слота. - Каждый инстанс слушает приватный адрес, кластерный порт 16379 закрыт для интернета.
- Задан пароль:
requirepass+masterauth, доступ закрыт по IP. - Проверен failover на живом кластере: запись восстановилась автоматически.
- Клиент — кластерный, с ретраями и таймаутами, а не «обычный Redis на порт мастера».
maxmemoryоставляет системе 25–30%, политика вытеснения осознанно выбрана.- Настроены бэкапы со всех мастеров на отдельную машину, восстановление проверено хотя бы раз.
- Есть мониторинг состояния кластера и алерты на
cluster_stateи место на диске. - Обновления делаются по одному узлу,
nodes.confруками не правится. - Приложение протестировано с недоступной репликой: читает с мастера и не падает.
Managed Redis или свой кластер
Коротко и без рекламы: это разные компромиссы, а не «хорошо/плохо».
Свой кластер на VPS. Дешевле по железу, полный доступ к конфигу и данным, никакой платформы-прослойки. Ценой идёт ваша работа: настройка, обновления, бэкапы, дежурство. Шесть небольших VPS на Tenku обходятся заметно дешевле managed-кластера похожей ёмкости — актуальные тарифы смотрите на странице VPS.
Managed-сервис. Провайдер берёт на себя обвязку: разворачивание, патчи, бэкапы, мониторинг, отказоустойчивость — с SLA (например, 99,95% на запись и 99,99% на чтение). Вы платите за это в разы больше и принимаете ограничения: нельзя произвольно менять версию или локацию после создания, доступ к файлам и внутренним настройкам ограничен. Часто это правильный выбор, когда у команды нет дежурного админа, а простой стоит дороже подписки.
Практическое правило: свой кластер берите, если вы умеете читать INFO и готовы дежурить; managed — если Redis нужен как инструмент, а не как проект.
Частые вопросы
Сколько серверов нужно для кластера Redis?
Минимум три мастера (для кворума при отказе) и хотя бы одна реплика на каждого — итого шесть машин. Конфигурация из трёх серверов по два инстанса рабочий эконом-вариант для тестов, но при отказе машины вы теряете сразу мастера и реплику.
Можно ли поставить кластер Redis на один VPS?
Технически — да, запустив несколько процессов на разных портах. Практического смысла мало: падение машины уносит весь кластер, вы получаете только шардинг по памяти. Такая схема годится для разработки и тестов логики приложения.
Какой порт нужен для кластера Redis?
Клиентский порт (по умолчанию 6379) и кластерный шина-порт, который всегда на 10 000 больше: 16379. Если открыть только 6379, узлы не смогут обмениваться служебными сообщениями, и кластер не соберётся.
Чем Redis Cluster отличается от Sentinel?
Sentinel даёт отказоустойчивость: три сервиса следят за мастером и выбирают нового при отказе. Но данные всё равно живут на одном узле, то есть память ограничена одним сервером. Cluster добавляет шардинг: данные распределены по слотам между мастерами, поэтому растёт и память, и пропускная способность.
Что будет с данными при отказе мастера?
Если у мастера есть реплика, она становится мастером за время около cluster-node-timeout (по умолчанию 15 секунд) плюс время выборов. Запись в это время недоступна для части слотов. Данные, которые успели записаться на мастер, сохраняются в пределах настроек репликации.
Реплика заменяет бэкап?
Нет. Реплика мгновенно повторяет любое изменение, включая ошибочное удаление ключей, поэтому она защищает от отказа железа, но не от ошибки или атаки. Бэкап — отдельный снимок (RDB/AOF), вынесенный на другую машину, с проверенным восстановлением.
Как понять, что кластер здоров?
cluster_state:ok, cluster_slots_assigned:16384, у каждого мастера есть реплика в состоянии connected, а redis-cli --cluster check не находит проблем. Эти три проверки стоит повесить в мониторинг как базовые.
Итог
Кластер Redis — это не «поставить пакет и забыть», а небольшая инфраструктура: шесть узлов, пароль, закрытые порты, понимание слотов и проверенный failover. Зато после сборки вы получаете хранилище, которое переживает отказ машины и растёт по памяти — просто добавляя узлы.
Под кластер удобно брать несколько одинаковых VPS: одинаковые ресурсы, одна локация, минимальный пинг между узлами. Конфигурации с NVMe и нужным объёмом RAM — на странице тарифов; если сомневаетесь, хватит ли памяти на ваши данные, начните с трёх узлов и теста на реальной нагрузке. А если Redis нужен только как кэш на пару сотен мегабайт, начните со обычного VPS и схемы master-slave — и переходите в кластер, когда упрётесь в память или в требования по доступности.