Высокая доступность Redis в производстве: операторы Sentinel, кластера и Kubernetes
Redis HA с Sentinel, режимом кластера и операторами Kubernetes
Redis — это основа современной инфраструктуры приложений. Он служит кэшем, хранилищем сеансов, брокером сообщений, ограничителем скорости, механизмом таблицы лидеров и конвейером аналитики в реальном времени для миллионов приложений по всему миру. Один экземпляр Redis может обрабатывать сотни тысяч операций в секунду с задержкой менее миллисекунды, но один экземпляр также является единственной точкой отказа. Когда Redis выходит из строя, в приложениях происходят каскадные сбои: кеши переполняют внутренние базы данных, сеансы теряются, ограничители скорости перестают работать, а функции реального времени отключаются. Создание высокодоступного развертывания Redis не является обязательным для производственных систем — это инженерное требование.
Это руководство представляет собой комплексное, ориентированное на производство подробное описание высокой доступности Redis. Мы рассмотрим основы репликации Redis (асинхронная репликация, команда WAIT и частичная ресинхронизация), Redis Sentinel для автоматического переключения при сбое и обнаружения сервисов, Redis Cluster для горизонтального масштабирования с распределением хеш-слотов, операторы Kubernetes (Spotahome, OpsTree и Redis Enterprise), стратегии персистентности (моментальные снимки RDB, AOF и гибридное персистентность), развертывания с облачным управлением на AWS. ElastiCache, Azure Cache для Redis и GCP Memorystore, развертывания k3s на «голом железе» с Rancher и Longhorn, политики управления памятью и вытеснения, шифрование TLS и контроль доступа на основе ACL, поведение Pub/Sub и Streams в конфигурациях высокой доступности, модули Redis (RedisJSON, RediSearch, RedisTimeSeries) в высокой доступности, пул соединений и конфигурация клиента для отказоустойчивость, стратегии резервного копирования и восстановления, мониторинг с помощью Redis INFO, средства экспорта Prometheus и информационных панелей Grafana, Dragonfly и KeyDB в качестве альтернатив, совместимых с Redis, настройка производительности с помощью конвейерной обработки, сценариев Lua и оптимизации памяти, типичные сценарии сбоев и процедуры устранения неполадок, а также стратегии планирования мощности и масштабирования.
Redis Основы репликации
Репликация Redis — это основа, на которой строятся все архитектуры высокой доступности. Главный экземпляр Redis принимает записи и асинхронно передает их одному или нескольким экземплярам реплик. Реплики поддерживают копию основного набора данных практически в реальном времени и обслуживают запросы на чтение, обеспечивая как избыточность данных, так и масштабируемость чтения.
В отличие от потоковой репликации PostgreSQL на базе WAL, Redis использует протокол репликации на основе команд. Каждая команда записи, выполняемая на ведущем устройстве, сериализуется в поток репликации и отправляется подключенным репликам, которые выполняют те же команды в отношении своих локальных наборов данных. Этот подход прост и эффективен, но имеет важные последствия для согласованности — поскольку репликация по умолчанию асинхронна, всегда существует окно, в котором подтвержденные записи на ведущем устройстве еще не достигли реплик.
Асинхронная репликация и команда WAIT
По умолчанию репликация Redis является полностью асинхронной. Мастер подтверждает запись клиенту сразу после ее локального применения, не дожидаясь, пока какая-либо реплика подтвердит получение. Это обеспечивает максимальную пропускную способность записи, но создает потенциальное окно потери данных — если мастер выйдет из строя до того, как запись достигнет какой-либо реплики, эта запись будет потеряна.
КомандаWAITобеспечивает примитив синхронной репликации. После выполнения записи клиент может вызватьWAIT numreplicas timeoutдля блокировки до тех пор, пока указанное количество реплик не подтвердит запись или не истечет время ожидания. Это не делает Redis полностью синхронным —WAITгарантирует только то, что реплики получили данные, а не то, что они были сохранены на диске реплик. Однако это существенно уменьшает окно потери данных.
# Write a critical value and wait for 2 replicas to acknowledge
SET order:12345 '{"status":"confirmed","amount":599.99}'
WAIT 2 5000
# Returns the number of replicas that acknowledged within 5000ms
# Returns 0 if no replica acknowledged (timeout or no replicas connected)ИспользуйтеWAITвыборочно для критических операций записи (финансовые транзакции, подтверждения заказов), позволяя при этом некритическим операциям записи (обновления кэша, обновления сеанса) выполняться асинхронно. Гибкость использования каждой команды позволяет избежать штрафов за задержку, связанных с полной синхронной репликацией.
Частичная ресинхронизация (PSYNC)
Когда реплика ненадолго отключается (сбой в сети, перезапуск), для повторного подключения ей не требуется полная передача набора данных. Redis поддерживает резервную копию репликации — циклический буфер последних команд записи — на ведущем устройстве. Когда реплика повторно подключается, она отправляет свое смещение репликации мастеру. Если смещение все еще находится в пределах очереди, мастер отправляет только недостающие команды (частичная повторная синхронизация). Если смещение вышло за пределы невыполненной работы, запускается полная ресинхронизация, которая включает в себя создание и передачу моментального снимка RDB.
# redis.conf — Replication backlog configuration
repl-backlog-size 256mb # Size of the replication backlog buffer
repl-backlog-ttl 3600 # Seconds to retain backlog after last replica disconnects
repl-diskless-sync yes # Transfer RDB via socket instead of disk (faster for full sync)
repl-diskless-sync-delay 5 # Wait 5s for more replicas before starting diskless sync
repl-diskless-sync-period 0 # No periodic full sync
repl-diskless-load on-empty-db # Replica loads RDB from socket directly into memoryПравильное определение размера очереди репликации имеет решающее значение. Он должен быть достаточно большим, чтобы вместить все команды записи, сгенерированные во время самого длительного ожидаемого отключения реплики. Для экземпляра Redis, обрабатывающего трафик записи со скоростью 50 МБ/с, резерв в 256 МБ покрывает около 5 секунд записи — увеличьте его, если ваши реплики могут быть отключены от сети в течение более длительных периодов времени.
Настройка репликации главной реплики
# redis.conf — Master configuration
bind 0.0.0.0
port 6379
protected-mode no
requirepass strong_master_password
masterauth strong_master_password
# Persistence
save 900 1
save 300 10
save 60 10000
appendonly yes
appendfsync everysec
aof-use-rdb-preamble yes
# Replication
repl-backlog-size 256mb
repl-backlog-ttl 3600
repl-diskless-sync yes
min-replicas-to-write 1 # Refuse writes if fewer than 1 replica connected
min-replicas-max-lag 10 # Replica considered disconnected if lag > 10 seconds# redis.conf — Replica configuration
bind 0.0.0.0
port 6379
protected-mode no
requirepass strong_master_password
masterauth strong_master_password
replicaof master-host 6379
replica-read-only yes
replica-serve-stale-data yes # Serve (possibly stale) data during sync
replica-priority 100 # Lower values get promoted first by SentinelНастройкиmin-replicas-to-writeиmin-replicas-max-lagне позволяют главному устройству принимать записи, если оно не может гарантировать надежность данных на репликах. Это критически важная система безопасности — без нее главный сетевой раздел продолжает принимать записи, которые будут потеряны, когда Sentinel продвигает реплику.
Redis Sentinel: автоматическое переключение при сбое и обнаружение сервисов
Redis Sentinel — это распределенная система, которая отслеживает экземпляры мастера и реплики Redis, обнаруживает сбои мастера, выполняет автоматический переход на другой ресурс путем повышения статуса реплики до уровня мастера и обеспечивает обнаружение служб, чтобы клиенты всегда могли найти текущий мастер. Sentinel работает как отдельный процесс вместе с Redis и работает через протокол консенсуса — кворум экземпляров Sentinel должен согласиться с тем, что главный сервер недоступен, прежде чем инициировать аварийное переключение.
Конфигурация SentinelДляSentinel требуется как минимум три экземпляра, чтобы выдержать один сбой Sentinel и при этом сохранить кворум. Каждый Sentinel контролирует одно и то же ведущее устройство Redis и связывается с другими Sentinelми посредством протокола сплетен, чтобы согласовать состояние здоровья ведущего устройства.
# /etc/redis/sentinel.conf — Sentinel instance configuration
port 26379
bind 0.0.0.0
protected-mode no
# Monitor the master named "mymaster" at 10.0.1.10:6379
# The quorum value (2) means 2 Sentinels must agree the master is down
sentinel monitor mymaster 10.0.1.10 6379 2
# Authentication
sentinel auth-pass mymaster strong_master_password
# Timing parameters
sentinel down-after-milliseconds mymaster 5000 # SDOWN after 5s of no PING response
sentinel failover-timeout mymaster 60000 # Max 60s for failover procedure
sentinel parallel-syncs mymaster 1 # Only 1 replica syncs from new master at a time
# Deny script execution for security
sentinel deny-scripts-reconfig yes
# Notification script (called on failover events)
# sentinel notification-script mymaster /opt/redis/notify.sh
# Client reconfiguration script (called when master changes)
# sentinel client-reconfig-script mymaster /opt/redis/reconfig.sh
# Logging
logfile /var/log/redis/sentinel.log
logevel notice
# Enable TLS for Sentinel communication
# tls-port 26379
# port 0
# tls-cert-file /etc/redis/tls/sentinel.crt
# tls-key-file /etc/redis/tls/sentinel.key
# tls-ca-cert-file /etc/redis/tls/ca.crt
# tls-replication yes
# tls-auth-clients optionalОбнаружение неисправностейSentinel работает в два этапа. Во-первых, отдельный Sentinel помечает ведущее устройство каксубъективно отключенным (SDOWN), когда он не получает действительного ответа на PING внутриdown-after-milliseconds. Затем, когда кворум Sentinels соглашается, что мастер недоступен, он помечается какObjectly Down (ODOWN)и начинается процесс переключения при отказе. Один Sentinel выбирается в качестве лидера аварийного переключения, который выбирает лучшую реплику (на основе приоритета, смещения репликации и идентификатора запуска), повышает ее до уровня главной, перенастраивает оставшиеся реплики для следования новому мастеру и обновляет состояние Sentinel.
Обнаружение службы Sentinel и настройка клиента
Ключевым преимуществом Sentinel по сравнению со статическими установками мастер-реплика является обнаружение сервисов. Клиенты не подключаются к фиксированному адресу Redis — они запрашивают у Sentinel текущий главный адрес и подписываются на уведомления об аварийном переключении. Каждая крупная клиентская библиотека Redis изначально поддерживает Sentinel.
# Node.js — ioredis with Sentinel support
const Redis = require('ioredis');
const redis = new Redis({
sentinels: [
{ host: '10.0.1.20', port: 26379 },
{ host: '10.0.1.21', port: 26379 },
{ host: '10.0.1.22', port: 26379 }
],
name: 'mymaster',
password: 'strong_master_password',
sentinelPassword: 'sentinel_password',
db: 0,
retryStrategy(times) {
const delay = Math.min(times * 200, 5000);
return delay;
},
reconnectOnError(err) {
const targetError = 'READONLY';
if (err.message.includes(targetError)) {
return true; // Reconnect on READONLY error (failover happened)
}
return false;
},
maxRetriesPerRequest: 3,
enableReadyCheck: true,
connectTimeout: 10000,
lazyConnect: false
});
redis.on('connect', () => console.log('Connected to Redis master'));
redis.on('error', (err) => console.error('Redis error:', err));
redis.on('+switch-master', (msg) => {
console.log('Master switched:', msg);
});# Python — redis-py with Sentinel support
from redis.sentinel import Sentinel
import redis
sentinel = Sentinel(
[('10.0.1.20', 26379), ('10.0.1.21', 26379), ('10.0.1.22', 26379)],
socket_timeout=5,
password='strong_master_password',
sentinel_kwargs={'password': 'sentinel_password'}
)
# Get a connection to the current master (for writes)
master = sentinel.master_for(
'mymaster',
socket_timeout=5,
retry_on_timeout=True,
db=0
)
# Get a connection to a replica (for reads)
replica = sentinel.slave_for(
'mymaster',
socket_timeout=5,
db=0
)
# Usage
master.set('session:user123', '{"logged_in": true}')
result = replica.get('session:user123')
print(result)// Go — go-redis with Sentinel support
package main
import (
"context"
"fmt"
"time"
"github.com/redis/go-redis/v9"
)
func main() {
ctx := context.Background()
rdb := redis.NewFailoverClient(&redis.FailoverOptions{
MasterName: "mymaster",
SentinelAddrs: []string{"10.0.1.20:26379", "10.0.1.21:26379", "10.0.1.22:26379"},
Password: "strong_master_password",
SentinelPassword: "sentinel_password",
DB: 0,
DialTimeout: 10 * time.Second,
ReadTimeout: 5 * time.Second,
WriteTimeout: 5 * time.Second,
PoolSize: 50,
MinIdleConns: 10,
MaxRetries: 3,
MinRetryBackoff: 200 * time.Millisecond,
MaxRetryBackoff: 5 * time.Second,
})
defer rdb.Close()
err := rdb.Set(ctx, "key", "value", 5*time.Minute).Err()
if err != nil {
fmt.Printf("Error: %v
", err)
return
}
val, err := rdb.Get(ctx, "key").Result()
if err != nil {
fmt.Printf("Error: %v
", err)
return
}
fmt.Printf("key = %s
", val)
}Кластер Redis: горизонтальное масштабирование с помощью хэш-слотов
В то время как Sentinel обеспечивает высокую доступность одного набора данных, Redis Cluster обеспечивает как высокую доступность, так и горизонтальное масштабирование. Кластер Redis распределяет данные по нескольким главным узлам с помощью механизма хэш-слотов — пространство ключей разделено на 16 384 хэш-слота, и каждый главный узел отвечает за подмножество этих слотов. Каждый мастер имеет одну или несколько реплик для аварийного переключения. В совокупности кластер обеспечивает автоматическое сегментирование, встроенную функцию аварийного переключения и возможность линейного масштабирования хранилища и пропускной способности путем добавления узлов.
Настройка кластера Redis
# Create a 6-node Redis Cluster (3 masters + 3 replicas)
# Each node needs a redis.conf with cluster-enabled
# redis.conf for each cluster node (adjust port per node)
port 7000
cluster-enabled yes
cluster-config-file nodes-7000.conf
cluster-node-timeout 5000
appendonly yes
appendfsync everysec
aof-use-rdb-preamble yes
requirepass cluster_password
masterauth cluster_password
bind 0.0.0.0
protected-mode no
repl-backlog-size 256mb
# Start all 6 Redis instances
redis-server /etc/redis/7000.conf
redis-server /etc/redis/7001.conf
# ... repeat for all 6 nodes
# Create the cluster
redis-cli --cluster create \
10.0.1.10:7000 10.0.1.11:7000 10.0.1.12:7000 \
10.0.1.13:7000 10.0.1.14:7000 10.0.1.15:7000 \
--cluster-replicas 1 \
-a cluster_password
# Verify cluster status
redis-cli -c -h 10.0.1.10 -p 7000 -a cluster_password cluster info
redis-cli -c -h 10.0.1.10 -p 7000 -a cluster_password cluster nodesПерешардинг и многоклавишные операции
Resharding перемещает хеш-слоты между мастерами для балансировки данных после добавления или удаления узлов. Во время перешардинга ключи в мигрирующих слотах могут получать перенаправления ASK, которые клиент обрабатывает прозрачно.
# Add a new node to the cluster
redis-cli --cluster add-node 10.0.1.16:7000 10.0.1.10:7000 -a cluster_password
# Reshard slots to the new node
redis-cli --cluster reshard 10.0.1.10:7000 \
--cluster-from all \
--cluster-to NEW_NODE_ID \
--cluster-slots 4096 \
--cluster-yes \
-a cluster_password
# Rebalance the cluster automatically
redis-cli --cluster rebalance 10.0.1.10:7000 -a cluster_password
# Check cluster slot distribution
redis-cli -c -h 10.0.1.10 -p 7000 -a cluster_password cluster slotsМногоключевые операции в кластере Redis работают только в том случае, если все задействованные ключи находятся в одном хэш-слоте. Используйте хэш-теги, чтобы гарантировать, что связанные ключи сопоставляются с одним и тем же слотом:{user:123}.profileи{user:123}.sessionsоба хешируются наuser:123, гарантируя, что они находятся на одном узле. Это позволяет использовать сценарии MGET, MSET, транзакции и Lua для связанных ключей.
# Hash tags ensure these keys are in the same slot
SET {order:5000}.details '{"item":"widget","qty":3}'
SET {order:5000}.payment '{"method":"card","status":"paid"}'
SET {order:5000}.shipping '{"carrier":"fedex","tracking":"FX123"}'
# Multi-key operations work because all keys share the {order:5000} hash tag
MGET {order:5000}.details {order:5000}.payment {order:5000}.shipping
# Transaction across same-slot keys
MULTI
SET {order:5000}.details '{"item":"widget","qty":3,"status":"confirmed"}'
SET {order:5000}.payment '{"method":"card","status":"captured"}'
EXECОператор Redis для Kubernetes
Использование Redis в Kubernetes требует тщательного обращения с постоянным хранилищем, сетевой идентификацией, плавным аварийным переключением и управлением конфигурацией. Операторы Kubernetes кодируют эти эксплуатационные знания в специальные контроллеры, которые декларативно управляют кластерами Redis с помощью пользовательских определений ресурсов (CRD).
Оператор Spotahome Redis
Оператор Spotahome (также известный как redis-operator) — это зрелый и широко используемый оператор для развертывания системы высокой доступности на базе Redis Sentinel в Kubernetes. Он управляет наборами главных реплик Redis с помощью аварийного переключения на базе Sentinel.
# Install the Spotahome Redis Operator
helm repo add spotahome https://spotahome.github.io/redis-operator
helm install redis-operator spotahome/redis-operator \
--namespace redis-system --create-namespace
# RedisFailover CRD — 3 Redis instances + 3 Sentinels
apiVersion: databases.spotahome.com/v1
kind: RedisFailover
metadata:
name: redis-ha
namespace: production
spec:
sentinel:
replicas: 3
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 200m
memory: 256Mi
customConfig:
down-after-milliseconds: "5000"
failover-timeout: "60000"
redis:
replicas: 3
resources:
requests:
cpu: "2"
memory: 8Gi
limits:
cpu: "4"
memory: 16Gi
storage:
persistentVolumeClaim:
metadata:
name: redis-data
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 50Gi
storageClassName: longhorn
customConfig:
maxmemory: "6gb"
maxmemory-policy: "allkeys-lru"
save: "900 1 300 10 60 10000"
appendonly: "yes"
appendfsync: "everysec"
aof-use-rdb-preamble: "yes"
repl-backlog-size: "256mb"
exporter:
enabled: true
image: oliver006/redis_exporter:latest
args:
- --include-system-metricsOpsTree Оператор Redis
Оператор OpsTree поддерживает топологии Redis Sentinel (автономная высокая доступность) и Redis Cluster (разделенная высокая доступность), что делает его более универсальным для различных сценариев использования.
# Install the OpsTree Redis Operator
helm repo add ot-helm https://ot-container-kit.github.io/helm-charts/
helm install redis-operator ot-helm/redis-operator \
--namespace redis-system --create-namespace
# Redis Cluster CRD — 3 masters + 3 replicas
apiVersion: redis.redis.opstreelabs.in/v1beta2
kind: RedisCluster
metadata:
name: redis-cluster
namespace: production
spec:
clusterSize: 3
clusterVersion: v7
persistenceEnabled: true
kubernetesConfig:
image: redis:7.2-alpine
imagePullPolicy: IfNotPresent
resources:
requests:
cpu: "2"
memory: 8Gi
limits:
cpu: "4"
memory: 16Gi
redisLeader:
replicas: 3
redisConfig:
additionalRedisConfig: |
maxmemory 6gb
maxmemory-policy allkeys-lru
appendonly yes
appendfsync everysec
redisFollower:
replicas: 3
redisConfig:
additionalRedisConfig: |
maxmemory 6gb
replica-read-only yes
storage:
volumeClaimTemplate:
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 50Gi
storageClassName: longhorn
redisExporter:
enabled: true
image: quay.io/opstree/redis-exporter:v1.44.0Redis Корпоративный оператор
Redis Enterprise предоставляет коммерческому оператору Kubernetes расширенные функции, включая активную-активную георепликацию (CRDT), поддержку модулей Redis, автоматическое распределение по уровням (ОЗУ + флэш-память) и автоматическое управление кластером. Это рекомендуемый вариант для организаций, которым необходимы соглашения об уровне обслуживания и поддержка корпоративного уровня.
# Redis Enterprise Operator CRD
apiVersion: app.redislabs.com/v1
kind: RedisEnterpriseCluster
metadata:
name: redis-enterprise
namespace: redis-enterprise
spec:
nodes: 3
persistentSpec:
enabled: true
storageClassName: longhorn
volumeSize: 100Gi
redisEnterpriseNodeResources:
limits:
cpu: "8"
memory: 32Gi
requests:
cpu: "4"
memory: 16Gi
uiServiceType: ClusterIP
servicesRiggerSpec:
databaseServiceType: ClusterIP
---
apiVersion: app.redislabs.com/v1alpha1
kind: RedisEnterpriseDatabase
metadata:
name: redis-ha-db
namespace: redis-enterprise
spec:
memorySize: 10GB
replication: true
shardCount: 3
persistence: aofEverySecond
tlsMode: enabled
modulesList:
- name: search
version: latest
- name: json
version: latestСтратегии сохранения: RDB, AOF и гибридный
Redis предлагает три механизма сохранения данных. Выбор правильной стратегии зависит от цели точки восстановления (RPO), требований к производительности и ограничений хранилища.
Снимки RDBсоздает снимки всего набора данных на определенный момент времени через заданные интервалы времени. Они компактны, быстро загружаются при перезапуске и идеально подходят для резервного копирования. Однако данные, записанные между снимками, теряются при сбое. RDB использует разветвленный дочерний процесс, поэтому создание моментального снимка не блокирует основной поток Redis, но само разветвление может вызвать резкий скачок задержки в больших наборах данных из-за выделения памяти при копировании при записи.
AOF (только добавление файла)регистрирует каждую операцию записи на диск. Он обеспечивает гораздо большую надежность, чем RDB — сappendfsync everysecвы теряете не более одной секунды данных при сбое. Сappendfsync alwaysвы ничего не теряете, но теряете значительную производительность. Файлы AOF больше, чем RDB, и медленнее загружаются при перезапуске.
Гибридное сохранение(рекомендуемый подход) сочетает в себе оба варианта:aof-use-rdb-preamble yesзаписывает снимок RDB в начале файла AOF, за которым следуют записи AOF для последующих записей. Это обеспечивает быстрое время запуска (раздел RDB) и высокую надежность (раздел AOF).
# redis.conf — Hybrid persistence (recommended for production)
# RDB snapshots
save 900 1 # Snapshot if at least 1 write in 900 seconds
save 300 10 # Snapshot if at least 10 writes in 300 seconds
save 60 10000 # Snapshot if at least 10000 writes in 60 seconds
stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes
dbfilename dump.rdb
dir /data/redis
# AOF
appendonly yes
appendfilename "appendonly.aof"
appendfsync everysec # Best balance of durability and performance
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
aof-use-rdb-preamble yes # Hybrid: RDB preamble + AOF tail
aof-timestamp-enabled yes # Enable timestamps for PITR (Redis 7+)
# Recovery options
rdb-del-sync-files no
aof-load-truncated yesРазвертывания Redis с облачным управлением
AWS ElastiCache для Redis
AWS ElastiCache предлагает полностью управляемый Redis с двумя режимами высокой доступности:с отключенным режимом кластера(один сегмент, до 5 реплик, аварийное переключение по принципу Sentinel) ис включенным режимом кластера(до 500 сегментов, каждый с 5 репликами, хэш-слот) распространение). Global Datastore обеспечивает межрегиональную репликацию для аварийного восстановления.
# AWS CLI — Create ElastiCache Redis Cluster Mode Enabled
aws elasticache create-replication-group \
--replication-group-id redis-ha-prod \
--replication-group-description "Production Redis HA Cluster" \
--engine redis \
--engine-version 7.1 \
--cache-node-type cache.r7g.2xlarge \
--num-node-groups 3 \
--replicas-per-node-group 2 \
--automatic-failover-enabled \
--multi-az-enabled \
--at-rest-encryption-enabled \
--transit-encryption-enabled \
--auth-token strong_auth_token \
--cache-subnet-group-name redis-subnet-group \
--security-group-ids sg-0123456789abcdef0 \
--snapshot-retention-limit 7 \
--snapshot-window "03:00-05:00" \
--preferred-maintenance-window "sun:05:00-sun:07:00" \
--cache-parameter-group-name redis-ha-params \
--log-delivery-configurations '[
{"LogType":"slow-log","DestinationType":"cloudwatch-logs","DestinationDetails":{"CloudWatchLogsDetails":{"LogGroup":"/aws/elasticache/redis-ha-prod"}}},
{"LogType":"engine-log","DestinationType":"cloudwatch-logs","DestinationDetails":{"CloudWatchLogsDetails":{"LogGroup":"/aws/elasticache/redis-ha-prod"}}}
]'
# Create Global Datastore for cross-region DR
aws elasticache create-global-replication-group \
--global-replication-group-id-suffix redis-global \
--primary-replication-group-id redis-ha-prod
# Add secondary region
aws elasticache create-replication-group \
--replication-group-id redis-ha-dr \
--replication-group-description "DR Redis in eu-west-2" \
--global-replication-group-id ldgnf-redis-global \
--cache-node-type cache.r7g.2xlarge \
--num-node-groups 3 \
--replicas-per-node-group 1 \
--region eu-west-2
# Custom parameter group for HA tuning
aws elasticache create-cache-parameter-group \
--cache-parameter-group-name redis-ha-params \
--cache-parameter-group-family redis7 \
--description "HA-optimised Redis 7 parameters"
aws elasticache modify-cache-parameter-group \
--cache-parameter-group-name redis-ha-params \
--parameter-name-values \
"ParameterName=maxmemory-policy,ParameterValue=allkeys-lru" \
"ParameterName=timeout,ParameterValue=300" \
"ParameterName=tcp-keepalive,ParameterValue=60" \
"ParameterName=activedefrag,ParameterValue=yes"Кэш Azure для Redis
КэшAzure для Redis предоставляет три уровня: базовый (без репликации), стандартный (реплицируемый) и премиум/корпоративный. Уровень «Премиум» поддерживает кластеризацию, георепликацию, избыточность зон, внедрение виртуальных сетей и сохранение данных. Уровень Enterprise добавляет модули Redis и географическое распределение «активный-активный».
# Azure CLI — Create Premium Azure Cache for Redis with clustering
az redis create \
--resource-group redis-ha-rg \
--name redis-ha-prod \
--location westeurope \
--sku Premium \
--vm-size P3 \
--shard-count 3 \
--replicas-per-master 1 \
--zones 1 2 3 \
--minimum-tls-version 1.2 \
--redis-version 7
# Enable geo-replication (link primary to secondary)
az redis server-link create \
--name redis-ha-prod \
--resource-group redis-ha-rg \
--server-to-link /subscriptions/.../redis-ha-dr \
--replication-role Secondary
# Configure data persistence
az redis update \
--name redis-ha-prod \
--resource-group redis-ha-rg \
--set redisConfiguration.rdb-backup-enabled=true \
--set redisConfiguration.rdb-backup-frequency=60 \
--set redisConfiguration.rdb-storage-connection-string="DefaultEndpointsProtocol=https;..."
# Enable diagnostics
az monitor diagnostic-settings create \
--name redis-diagnostics \
--resource /subscriptions/.../redis-ha-prod \
--workspace /subscriptions/.../log-analytics-workspace \
--metrics '[{"category":"AllMetrics","enabled":true}]'Память GCP для Redis
GCP предлагает два уровня Memorystore:Standard(один экземпляр с автоматической репликой аварийного переключения) иRedis Cluster(разделенный, полностью управляемый кластер с автоматическим масштабированием). Уровень Standard подходит для большинства случаев использования высокой доступности, а кластер Redis обрабатывает большие наборы данных, требующие горизонтального масштабирования.
# GCP — Create Standard tier Memorystore (HA with auto-failover)
gcloud redis instances create redis-ha-prod \
--size=26 \
--region=europe-west1 \
--zone=europe-west1-b \
--alternative-zone=europe-west1-c \
--tier=standard \
--redis-version=redis_7_2 \
--redis-config="maxmemory-policy=allkeys-lru,activedefrag=yes" \
--network=projects/my-project/global/networks/vpc-main \
--transit-encryption-mode=SERVER_AUTHENTICATION \
--enable-auth \
--persistence-mode=RDB \
--rdb-snapshot-period=12h \
--rdb-snapshot-start-time="2026-04-12T03:00:00Z" \
--maintenance-window-day=SUNDAY \
--maintenance-window-hour=4
# GCP — Create Memorystore Redis Cluster
gcloud redis clusters create redis-cluster-prod \
--region=europe-west1 \
--shard-count=3 \
--replica-count=1 \
--network=projects/my-project/global/networks/vpc-main \
--transit-encryption-mode=SERVER_AUTHENTICATIONРазвертывание Redis в нескольких регионах
Развертывание Redis в нескольких регионах необходимо для аварийного восстановления и глобального сокращения задержек. Подход зависит от архитектуры: Redis Enterprise использует Active-Active с CRDT (бесконфликтные реплицируемые типы данных) для настоящей записи с несколькими главными устройствами, в то время как Redis с открытым исходным кодом и службы с облачным управлением используют активно-пассивную репликацию с репликами чтения во вторичных регионах.
Bare Metal k3s/Rancher с Longhorn
Для организаций, использующих собственное оборудование, развертывание Redis HA на «голом железе» k3s обеспечивает полный контроль над инфраструктурой, устраняет привязку к облачному поставщику и может быть значительно более рентабельным для крупномасштабных развертываний. k3s — это легкий, сертифицированный дистрибутив Kubernetes, идеально подходящий для периферийных сред и сред с «голым железом», а Rancher обеспечивает плоскость управления для многокластерных операций.
Установка k3s и развертывание Redis оператором
# Install k3s on the first server node
curl -sfL https://get.k3s.io | K3S_TOKEN=redis-cluster-token \
INSTALL_K3S_EXEC="server --cluster-init --disable traefik --disable servicelb" sh -
# Join additional server nodes
curl -sfL https://get.k3s.io | K3S_TOKEN=redis-cluster-token \
K3S_URL=https://10.0.0.1:6443 \
INSTALL_K3S_EXEC="server" sh -
# Install Longhorn for distributed block storage
helm repo add longhorn https://charts.longhorn.io
helm install longhorn longhorn/longhorn \
--namespace longhorn-system --create-namespace \
--set defaultSettings.defaultDataPath=/mnt/longhorn \
--set defaultSettings.replicaCount=3 \
--set defaultSettings.storageMinimalAvailablePercentage=15
# Install MetalLB for bare-metal LoadBalancer services
helm repo add metallb https://metallb.github.io/metallb
helm install metallb metallb/metallb --namespace metallb-system --create-namespace
# Configure MetalLB IP address pool
kubectl apply -f - <Redis HA Helm Значения для k3s
# values-redis-ha.yaml — Helm values for Redis HA on k3s/Longhorn
redis:
replicas: 3
resources:
requests:
cpu: "2"
memory: 8Gi
limits:
cpu: "4"
memory: 16Gi
storage:
persistentVolumeClaim:
metadata:
name: redis-data
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 50Gi
storageClassName: longhorn
customConfig:
maxmemory: "6gb"
maxmemory-policy: "allkeys-lru"
save: "900 1 300 10 60 10000"
appendonly: "yes"
appendfsync: "everysec"
aof-use-rdb-preamble: "yes"
repl-backlog-size: "256mb"
tcp-keepalive: "60"
timeout: "300"
hz: "10"
activedefrag: "yes"
exporter:
enabled: true
image: oliver006/redis_exporter:latest
sentinel:
replicas: 3
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 200m
memory: 256Mi
customConfig:
down-after-milliseconds: "5000"
failover-timeout: "60000"
parallel-syncs: "1"
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app.kubernetes.io/component
operator: In
values:
- redis
topologyKey: kubernetes.io/hostnameУправление памятью и политики вытеснения
Redis хранит все данные в памяти, что делает управление памятью наиболее важной эксплуатационной задачей. Когда Redis достигает настроенного пределаmaxmemory, он должен решить, что делать с входящими командами записи. Политика выселения контролирует такое поведение.
# redis.conf — Memory management
maxmemory 6gb
maxmemory-policy allkeys-lru
# Available eviction policies:
# noeviction — Return errors on writes when memory limit reached
# allkeys-lru — Evict least recently used keys (general-purpose cache)
# allkeys-lfu — Evict least frequently used keys (better for skewed access patterns)
# volatile-lru — Evict LRU keys with TTL set
# volatile-lfu — Evict LFU keys with TTL set
# volatile-ttl — Evict keys with shortest TTL first
# allkeys-random — Evict random keys
# volatile-random — Evict random keys with TTL set
# Active defragmentation (Redis 4.0+)
activedefrag yes
active-defrag-enabled yes
active-defrag-ignore-bytes 100mb
active-defrag-threshold-lower 10
active-defrag-threshold-upper 100
active-defrag-cycle-min 1
active-defrag-cycle-max 25
active-defrag-max-scan-fields 1000
# Memory usage monitoring
# redis-cli INFO memory
# Key metrics:
# used_memory — Total bytes allocated by Redis
# used_memory_rss — Resident set size (OS-level memory)
# mem_fragmentation_ratio — RSS / used_memory (should be close to 1.0)
# maxmemory — Configured memory limit
# evicted_keys — Total keys evicted due to maxmemoryДля развертываний высокой доступности установите дляmaxmemoryзначение примерно 75 % доступной оперативной памяти узла. Остальные 25% занимают выходной буфер репликации, буфер перезаписи AOF, память копирования при записи во время снимков RDB и служебные данные ОС. Для модуля емкостью 16 ГБ установите для параметра maxmemory значение 12 ГБ. Для «голого» сервера емкостью 64 ГБ установите значение 48 ГБ.
Шифрование TLS и списки управления доступом
Производственные развертывания Redis должны шифровать передаваемые данные с помощью TLS и обеспечивать детальный контроль доступа с помощью ACL (списков управления доступом), представленных в Redis 6.0.
# redis.conf — TLS configuration
tls-port 6380
port 0 # Disable non-TLS port entirely
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-auth-clients optional # Require client certificates (mutual TLS)
tls-replication yes # Encrypt replication traffic
tls-cluster yes # Encrypt cluster bus traffic
tls-protocols "TLSv1.3" # Only allow TLS 1.3
# ACL configuration (Redis 6.0+)
# user on|off [>password] [~pattern] [+command|-command] [&channel]
user default off # Disable the default user
user admin on >strong_admin_pass ~* +@all
user appuser on >app_pass ~app:* ~session:* ~cache:* +@read +@write +@connection -@admin -@dangerous
user readonly on >readonly_pass ~* +@read +@connection -@write -@admin
user replicator on >repl_pass +psync +replconf +ping
# Load ACL from external file
aclfile /etc/redis/users.acl Pub/Sub и потоки в настройках высокой доступности
Redis Pub/Sub и потоки ведут себя по-разному в конфигурациях высокой доступности. Понимание этих различий необходимо для создания надежных систем, управляемых событиями.
Pub/Sub Сообщенияработают по принципу «запустил и забыл» — они не сохраняются, не реплицируются и не буферизуются. При настройке высокой доступности на основе Sentinel подписчики, подключенные к главному устройству, получают сообщения в обычном режиме, но во время аварийного переключения новый главный узел не имеет информации о предыдущих подписках. Клиенты должны повторно подписаться после повторного подключения. В кластере Redis сообщения Pub/Sub передаются всем узлам кластера, поэтому подписчики, подключенные к любому узлу, получают опубликованные сообщения (хотя при этом генерируется межузловой трафик).
Потоки Redis— это постоянная реплицируемая структура данных, обеспечивающая надежную доставку сообщений в средах высокой доступности. Записи потока реплицируются в реплики с помощью обычного механизма репликации, выдерживают отработку отказа и поддерживают группы потребителей с семантикой доставки хотя бы один раз. Для обмена сообщениями высокой доступности всегда следует отдавать предпочтение потокам, а не Pub/Sub.
# Redis Streams with consumer groups — HA-safe message processing
# Create a stream and consumer group
XGROUP CREATE events:orders orders-processors $ MKSTREAM
# Produce events
XADD events:orders * action "order_placed" order_id "12345" amount "599.99"
XADD events:orders * action "order_placed" order_id "12346" amount "149.99"
# Consume events (in consumer group — at-least-once delivery)
XREADGROUP GROUP orders-processors worker-1 COUNT 10 BLOCK 5000 STREAMS events:orders >
# Acknowledge processed events
XACK events:orders orders-processors 1681234567890-0
# Check pending messages (unacknowledged)
XPENDING events:orders orders-processors - + 10
# Claim abandoned messages (from a dead consumer)
XAUTOCLAIM events:orders orders-processors worker-2 60000 0-0 COUNT 10
# Trim stream to prevent unbounded growth
XTRIM events:orders MAXLEN ~ 100000Модули Redis в системе высокой доступности
Модули Redis расширяют Redis специализированными структурами данных и функциональностью. Три наиболее популярных — RedisJSON, RediSearch и RedisTimeSeries — работают с репликацией и Sentinel, но имеют особые особенности при развертывании высокой доступности.
# redis.conf — Loading modules
loadmodule /opt/redis-stack/lib/rejson.so
loadmodule /opt/redis-stack/lib/redisearch.so
loadmodule /opt/redis-stack/lib/redistimeseries.so
# Modules are replicated to replicas via the command stream
# Ensure the same modules are installed on all nodes (master + replicas)
# RedisJSON — store and query JSON documents
JSON.SET user:1001 $ '{"name":"Alice","email":"alice@example.com","orders":42}'
JSON.GET user:1001 $.name
# RediSearch — full-text search with indexing
FT.CREATE idx:users ON JSON PREFIX 1 user: SCHEMA $.name AS name TEXT $.email AS email TAG $.orders AS orders NUMERIC
FT.SEARCH idx:users "@name:Alice"
# RedisTimeSeries — time-series data
TS.CREATE metrics:cpu:node1 RETENTION 86400000 LABELS host node1 metric cpu
TS.ADD metrics:cpu:node1 * 73.5
TS.RANGE metrics:cpu:node1 - + AGGREGATION avg 60000При запуске стека Redis (пакета модулей) в системе высокой доступности убедитесь, что на всех узлах — главном и репликах — установлены одинаковые версии модулей. Команды модуля реплицируются через стандартный поток репликации, поэтому реплики должны иметь возможность их выполнять. После отработки отказа индексы RediSearch существуют в повышенной реплике и немедленно обслуживают запросы.
Пул соединений и настройка клиента для HA
Правильное группирование соединений имеет важное значение для производительности и устойчивости Redis HA. Пулы соединений сокращают затраты на установление TCP-соединений, обеспечивают автоматическую логику повторных попыток и обеспечивают плавную обработку отказа.
# Node.js — ioredis connection pool with cluster mode
const Redis = require('ioredis');
// Cluster mode connection
const cluster = new Redis.Cluster(
[
{ host: '10.0.1.10', port: 7000 },
{ host: '10.0.1.11', port: 7000 },
{ host: '10.0.1.12', port: 7000 }
],
{
redisOptions: {
password: 'cluster_password',
connectTimeout: 10000,
maxRetriesPerRequest: 3
},
scaleReads: 'slave', // Route reads to replicas
clusterRetryStrategy(times) {
return Math.min(times * 200, 5000);
},
slotsRefreshTimeout: 2000,
slotsRefreshInterval: 5000,
enableOfflineQueue: true,
enableReadyCheck: true,
natMap: {} // For NAT/port-forwarded environments
}
);
cluster.on('error', (err) => console.error('Cluster error:', err));
cluster.on('node error', (err, address) => {
console.error(`Node ${address} error:`, err);
});# Python — redis-py connection pool with cluster mode
from redis.cluster import RedisCluster
from redis.backoff import ExponentialBackoff
from redis.retry import Retry
retry = Retry(ExponentialBackoff(cap=5, base=0.1), retries=5)
rc = RedisCluster(
startup_nodes=[
{"host": "10.0.1.10", "port": 7000},
{"host": "10.0.1.11", "port": 7000},
{"host": "10.0.1.12", "port": 7000}
],
password="cluster_password",
decode_responses=True,
read_from_replicas=True,
retry=retry,
retry_on_timeout=True,
socket_timeout=5,
socket_connect_timeout=5,
max_connections=50,
health_check_interval=30
)
rc.set("key", "value")
print(rc.get("key"))// Go — go-redis cluster client with connection pooling
package main
import (
"context"
"time"
"github.com/redis/go-redis/v9"
)
func NewRedisCluster() *redis.ClusterClient {
return redis.NewClusterClient(&redis.ClusterOptions{
Addrs: []string{
"10.0.1.10:7000",
"10.0.1.11:7000",
"10.0.1.12:7000",
},
Password: "cluster_password",
ReadOnly: true,
RouteRandomly: true,
RouteByLatency: false,
PoolSize: 50,
MinIdleConns: 10,
DialTimeout: 10 * time.Second,
ReadTimeout: 5 * time.Second,
WriteTimeout: 5 * time.Second,
PoolTimeout: 10 * time.Second,
MaxRetries: 5,
MinRetryBackoff: 200 * time.Millisecond,
MaxRetryBackoff: 5 * time.Second,
})
}Стратегии резервного копирования и восстановления
Даже при репликации высокой доступности регулярное резервное копирование необходимо для аварийного восстановления, обеспечения соответствия требованиям и защиты от логических ошибок (случайное FLUSHALL, неверная запись приложения). Резервные копии Redis основаны на моментальных снимках RDB и файлах AOF.
#!/bin/bash
# redis-backup.sh — Automated Redis backup script
REDIS_HOST="10.0.1.10"
REDIS_PORT="6379"
REDIS_PASS="strong_master_password"
BACKUP_DIR="/backups/redis"
S3_BUCKET="s3://redis-backups-prod"
RETENTION_DAYS=30
DATE=$(date +%Y%m%d_%H%M%S)
mkdir -p "$BACKUP_DIR"
# Trigger RDB snapshot on the master
redis-cli -h "$REDIS_HOST" -p "$REDIS_PORT" -a "$REDIS_PASS" BGSAVE
# Wait for background save to complete
while [ "$(redis-cli -h $REDIS_HOST -p $REDIS_PORT -a $REDIS_PASS LASTSAVE)" = "$(redis-cli -h $REDIS_HOST -p $REDIS_PORT -a $REDIS_PASS LASTSAVE)" ]; do
sleep 1
done
sleep 2
# Copy the RDB file
RDB_FILE=$(redis-cli -h "$REDIS_HOST" -p "$REDIS_PORT" -a "$REDIS_PASS" CONFIG GET dir | tail -1)
cp "${RDB_FILE}/dump.rdb" "${BACKUP_DIR}/dump_${DATE}.rdb"
# Compress and upload to S3
gzip "${BACKUP_DIR}/dump_${DATE}.rdb"
aws s3 cp "${BACKUP_DIR}/dump_${DATE}.rdb.gz" "${S3_BUCKET}/daily/dump_${DATE}.rdb.gz" \
--storage-class STANDARD_IA
# Cleanup old local backups
find "$BACKUP_DIR" -name "dump_*.rdb.gz" -mtime +$RETENTION_DAYS -delete
# Verify backup integrity
redis-check-rdb "${BACKUP_DIR}/dump_${DATE}.rdb.gz" && \
echo "Backup verified: dump_${DATE}.rdb.gz" || \
echo "ERROR: Backup verification failed!"
echo "Backup complete: ${BACKUP_DIR}/dump_${DATE}.rdb.gz"# Restore from RDB backup
# 1. Stop Redis
systemctl stop redis
# 2. Replace the RDB file
gunzip /backups/redis/dump_20260412_030000.rdb.gz
cp /backups/redis/dump_20260412_030000.rdb /data/redis/dump.rdb
chown redis:redis /data/redis/dump.rdb
# 3. Disable AOF temporarily (if enabled) to prevent AOF overriding RDB on startup
redis-cli -a password CONFIG SET appendonly no
# 4. Start Redis (loads RDB)
systemctl start redis
# 5. Re-enable AOF and rewrite it from the loaded data
redis-cli -a password CONFIG SET appendonly yes
redis-cli -a password BGREWRITEAOFМониторинг с помощью Redis INFO, Prometheus и Grafana
Комплексный мониторинг — основа безупречной работы Redis HA. Redis предоставляет богатые внутренние метрики с помощью командыINFO, которые средство экспорта Prometheus Redis преобразует в метрики временных рядов для информационных панелей и оповещений Grafana.
# Key Redis INFO sections for HA monitoring
redis-cli -a password INFO replication
# role:master
# connected_slaves:2
# slave0:ip=10.0.1.11,port=6379,state=online,offset=1234567,lag=0
# slave1:ip=10.0.1.12,port=6379,state=online,offset=1234560,lag=1
# master_replid:abc123...
# master_repl_offset:1234567
# repl_backlog_size:268435456
# repl_backlog_first_byte_offset:1000000
redis-cli -a password INFO memory
# used_memory:6442450944
# used_memory_human:6.00G
# used_memory_rss:6879707136
# mem_fragmentation_ratio:1.07
# maxmemory:6442450944
# maxmemory_policy:allkeys-lru
# evicted_keys:12345
redis-cli -a password INFO stats
# total_connections_received:50000
# total_commands_processed:12345678
# instantaneous_ops_per_sec:85432
# keyspace_hits:11000000
# keyspace_misses:1345678
# expired_keys:500000
# evicted_keys:12345
redis-cli -a password INFO clients
# connected_clients:150
# blocked_clients:0
# maxclients:10000# Prometheus Redis Exporter deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: redis-exporter
namespace: monitoring
spec:
replicas: 1
selector:
matchLabels:
app: redis-exporter
template:
metadata:
labels:
app: redis-exporter
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "9121"
spec:
containers:
- name: redis-exporter
image: oliver006/redis_exporter:latest
args:
- --redis.addr=redis://redis-ha-master:6379
- --redis.password=$(REDIS_PASSWORD)
- --include-system-metrics
- --is-cluster
env:
- name: REDIS_PASSWORD
valueFrom:
secretKeyRef:
name: redis-secret
key: password
ports:
- containerPort: 9121
name: metrics
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 200m
memory: 256Mi# PrometheusRule for Redis HA alerts
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: redis-ha-alerts
namespace: monitoring
spec:
groups:
- name: redis-availability
rules:
- alert: RedisDown
expr: redis_up == 0
for: 1m
labels:
severity: critical
annotations:
summary: "Redis instance {{ $labels.instance }} is down"
- alert: RedisReplicaDisconnected
expr: redis_connected_slaves < 2
for: 2m
labels:
severity: warning
annotations:
summary: "Redis master has fewer than 2 connected replicas"
- alert: RedisReplicationLagHigh
expr: redis_replication_lag > 5
for: 3m
labels:
severity: warning
annotations:
summary: "Redis replication lag exceeds 5 seconds on {{ $labels.instance }}"
- alert: RedisMemoryUsageHigh
expr: redis_memory_used_bytes / redis_memory_max_bytes > 0.9
for: 5m
labels:
severity: warning
annotations:
summary: "Redis memory usage above 90% on {{ $labels.instance }}"
- alert: RedisEvictionsHigh
expr: rate(redis_evicted_keys_total[5m]) > 100
for: 5m
labels:
severity: warning
annotations:
summary: "Redis evicting keys at >100/s on {{ $labels.instance }}"
- alert: RedisKeyspaceHitRateLow
expr: redis_keyspace_hits_total / (redis_keyspace_hits_total + redis_keyspace_misses_total) < 0.8
for: 10m
labels:
severity: info
annotations:
summary: "Redis cache hit rate below 80% on {{ $labels.instance }}"
- alert: RedisSentinelDown
expr: redis_sentinel_master_status != 1
for: 1m
labels:
severity: critical
annotations:
summary: "Redis Sentinel reports master unhealthy"
- name: redis-performance
rules:
- alert: RedisSlowlogGrowing
expr: increase(redis_slowlog_length[5m]) > 10
for: 5m
labels:
severity: warning
annotations:
summary: "Redis slow log growing rapidly on {{ $labels.instance }}"
- alert: RedisConnectionsNearLimit
expr: redis_connected_clients / redis_config_maxclients > 0.8
for: 5m
labels:
severity: warning
annotations:
summary: "Redis connected clients above 80% of maxclients"Dragonfly и KeyDB: Redis-совместимые альтернативы
Хотя Redis является доминирующим хранилищем данных в памяти, две альтернативы, совместимые с Redis, получили распространение для конкретных случаев использования.
Стрекоза
Dragonfly — это современная многопоточная замена Redis, которая призвана стать быстрой заменой, используя при этом все доступные ядра CPU. Традиционный Redis является однопоточным для обработки команд — Dragonfly использует архитектуру без разделяемого доступа с несколькими потоками для достижения значительно более высокой пропускной способности на многоядерных машинах. Он поддерживает протокол Redis, большинство команд Redis и может заменить Redis без внесения изменений в приложение.
# Run Dragonfly as a Redis replacement
docker run -d --name dragonfly \
-p 6379:6379 \
-v /data/dragonfly:/data \
docker.dragonflydb.io/dragonflydb/dragonfly \
--maxmemory 12gb \
--proactor_threads 8 \
--dbfilename dump.rdb \
--requirepass strong_password
# Dragonfly in Kubernetes
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: dragonfly
namespace: production
spec:
replicas: 1
selector:
matchLabels:
app: dragonfly
template:
metadata:
labels:
app: dragonfly
spec:
containers:
- name: dragonfly
image: docker.dragonflydb.io/dragonflydb/dragonfly:latest
args:
- --maxmemory=12gb
- --proactor_threads=8
- --requirepass=strong_password
- --snapshot_cron=*/30 * * * *
ports:
- containerPort: 6379
resources:
requests:
cpu: "4"
memory: 16Gi
limits:
cpu: "8"
memory: 16Gi
volumeMounts:
- name: data
mountPath: /data
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: ["ReadWriteOnce"]
storageClassName: longhorn
resources:
requests:
storage: 100GiКлючевые преимуществаDragonfly: многопоточный режим (25-кратная пропускная способность на 8 ядрах по сравнению с однопоточным Redis), повышенная эффективность использования памяти (используются хеш-таблицы Dash вместо dict Redis), встроенная функция создания снимков без накладных расходов fork() и встроенная поддержка больших наборов данных. Однако по состоянию на 2026 год поддержка репликации Dragonfly все еще находится на стадии зрелости — она поддерживает репликацию первичной реплики, но еще не имеет системы автоматического переключения при отказе, эквивалентной Sentinel. Для обеспечения высокой доступности используйте проверки работоспособности Kubernetes и политики перезапуска StatefulSet или разверните за балансировщиком нагрузки с аварийным переключением на уровне приложения.
База данных ключей
KeyDB — это многопоточная версия Redis, поддерживаемая Snap (компанией, стоящей за Snapchat). Он полностью совместим с Redis и добавляет многопоточность, репликацию «активный-активный» (мульти-мастер), многоуровневое хранение флэш-памяти и истечение срока действия подраздела. Репликация «активный-активный» KeyDB особенно интересна для высокой доступности — два экземпляра KeyDB могут одновременно принимать записи и реплицировать друг друга, обеспечивая аварийное переключение с нулевым временем простоя.
# keydb.conf — Multi-threaded configuration with active replication
server-threads 4 # Use 4 threads for command processing
bind 0.0.0.0
port 6379
requirepass strong_password
masterauth strong_password
# Active-active replication (multi-master)
active-replica yes
replicaof peer-host 6379 # Bidirectional replication
# On the peer node, configure the reverse:
# replicaof this-host 6379
# FLASH storage tiering (for datasets larger than RAM)
# storage-provider flash /mnt/flash-storage 100
# maxmemory 16gb
# Will keep hot data in RAM and spill cold data to SSD
# SubKey expiration (unique to KeyDB)
# Allows setting TTL on hash fields, not just top-level keys
# EXPIREMEMBER myhash field1 3600KeyDB — хороший выбор, когда вам нужна репликация с несколькими хозяевами для географического распределения или обслуживания без простоев, или когда вам нужна более высокая пропускная способность, чем может обеспечить однопоточный Redis, но вы хотите оставаться ближе к кодовой базе Redis, чем Dragonfly.
Настройка производительностиТрубопроводная система
Конвейерная обработкаобъединяет несколько команд в одну двустороннюю сеть, что значительно снижает задержку при массовых операциях. Вместо ожидания каждого ответа перед отправкой следующей команды клиент отправляет все команды одновременно и считывает все ответы вместе.
# Python — Pipelining with redis-py
import redis
import time
r = redis.Redis(host='10.0.1.10', port=6379, password='password', decode_responses=True)
# Without pipelining: 1000 round-trips
start = time.time()
for i in range(1000):
r.set(f'key:{i}', f'value:{i}')
print(f'Without pipeline: {time.time() - start:.3f}s')
# With pipelining: 1 round-trip for 1000 commands
start = time.time()
pipe = r.pipeline(transaction=False)
for i in range(1000):
pipe.set(f'key:{i}', f'value:{i}')
pipe.execute()
print(f'With pipeline: {time.time() - start:.3f}s')
# Typically 5-10x fasterLua-скрипты
Сценарии Luaвыполняются на сервере Redis атомарно, исключая повторные циклы выполнения сложных операций и гарантируя, что между операциями сценария не будет выполняться никакая другая команда. В кластере Redis убедитесь, что все ключи, к которым осуществляется доступ с помощью сценария Lua, находятся в одном и том же хеш-слоте, используя хеш-теги.
# Lua script for atomic rate limiting
# KEYS[1] = rate limit key
# ARGV[1] = max requests
# ARGV[2] = window in seconds
local current = redis.call('INCR', KEYS[1])
if current == 1 then
redis.call('EXPIRE', KEYS[1], ARGV[2])
end
if current > tonumber(ARGV[1]) then
return 0 -- Rate limited
end
return 1 -- Allowed
# Load and execute
redis-cli -a password EVAL "\
local current = redis.call('INCR', KEYS[1]) \
if current == 1 then redis.call('EXPIRE', KEYS[1], ARGV[2]) end \
if current > tonumber(ARGV[1]) then return 0 end \
return 1" 1 ratelimit:user:123 100 60Оптимизация памяти
# redis.conf — Memory optimisation settings
# Use ziplist encoding for small hashes, lists, sorted sets
hash-max-listpack-entries 128
hash-max-listpack-value 64
list-max-listpack-size -2 # 8KB per node
zset-max-listpack-entries 128
zset-max-listpack-value 64
set-max-intset-entries 512
# Lazy freeing (avoid blocking on large key deletion)
lazyfree-lazy-eviction yes
lazyfree-lazy-expire yes
lazyfree-lazy-server-del yes
lazyfree-lazy-user-del yes
lazyfree-lazy-user-flush yes
# jemalloc tuning
# MALLOC_CONF="background_thread:true,dirty_decay_ms:5000,muzzy_decay_ms:5000"
# Analyse memory usage
redis-cli -a password MEMORY DOCTOR
redis-cli -a password MEMORY STATS
redis-cli -a password --bigkeys
redis-cli -a password --memkeysРаспространенные сценарии сбоев и устранение неполадок
Сценарий 1: мастер выходит из строя, Sentinel продвигает реплику
# Diagnosis
redis-cli -p 26379 SENTINEL master mymaster
# Check: flags should show 's_down' or 'o_down' if master is unreachable
redis-cli -p 26379 SENTINEL get-master-addr-by-name mymaster
# Returns the current master address (should be the promoted replica)
# Check Sentinel logs for failover events
tail -f /var/log/redis/sentinel.log
# Look for: +sdown, +odown, +try-failover, +elected-leader,
# +failover-state-select-slave, +selected-slave,
# +failover-state-send-slaveof-noone, +failover-endСценарий 2: разделенный мозг с двумя ведущими устройствами
# Diagnosis: check if min-replicas-to-write is configured
redis-cli -a password CONFIG GET min-replicas-to-write
redis-cli -a password CONFIG GET min-replicas-max-lag
# Prevention: configure min-replicas on all masters
redis-cli -a password CONFIG SET min-replicas-to-write 1
redis-cli -a password CONFIG SET min-replicas-max-lag 10
# If split-brain occurred: identify the stale master
# Compare replication offsets — the master with the higher offset has more data
redis-cli -h master1-ip -a password INFO replication | grep master_repl_offset
redis-cli -h master2-ip -a password INFO replication | grep master_repl_offset
# Force the stale master to become a replica
redis-cli -h stale-master-ip -a password REPLICAOF correct-master-ip 6379Сценарий 3: Шторм полной повторной синхронизации после раздела сети
# Diagnosis: check replication backlog
redis-cli -a password INFO replication | grep repl_backlog
# If repl_backlog_first_byte_offset is ahead of replica's offset, full sync triggers
# Prevention: increase backlog size
redis-cli -a password CONFIG SET repl-backlog-size 512mb
# Monitor for full syncs
redis-cli -a password INFO stats | grep sync_full
redis-cli -a password INFO stats | grep sync_partial_ok
redis-cli -a password INFO stats | grep sync_partial_errСценарий 4: исчерпание памяти и прекращение работы OOM
# Diagnosis
redis-cli -a password INFO memory
# Check: used_memory vs maxmemory, mem_fragmentation_ratio
redis-cli -a password MEMORY DOCTOR
# Returns advice on memory issues
# Prevention: set proper maxmemory and eviction
redis-cli -a password CONFIG SET maxmemory 12gb
redis-cli -a password CONFIG SET maxmemory-policy allkeys-lru
# Find large keys consuming memory
redis-cli -a password --bigkeys
redis-cli -a password --memkeys --memkeys-samples 100
# Emergency: manually evict keys
redis-cli -a password SCAN 0 COUNT 1000 TYPE string
# Identify and DEL unnecessary large keysСценарий 5: медленные команды блокируют репликацию
# Diagnosis: check slowlog
redis-cli -a password SLOWLOG GET 20
redis-cli -a password SLOWLOG LEN
# Check for blocking commands
redis-cli -a password CLIENT LIST | grep -E 'cmd=(keys|sort|smembers)'
# Prevention: configure slowlog threshold
redis-cli -a password CONFIG SET slowlog-log-slower-than 10000 # 10ms
redis-cli -a password CONFIG SET slowlog-max-len 256
# Rename dangerous commands
rename-command KEYS "" # Disable KEYS entirely
rename-command FLUSHALL "" # Disable FLUSHALL
rename-command FLUSHDB "" # Disable FLUSHDB
rename-command DEBUG "" # Disable DEBUGСтратегии планирования емкости и масштабирования
Планирование емкостидля Redis HA включает оценку требований к памяти, пропускной способности сети и использования CPU на главных узлах и узлах-репликах. Ключевыми показателями для планирования являются размер набора данных, количество операций в секунду, средний размер ключа/значения и затраты на репликацию.
# Capacity estimation formulas
# Memory per node:
# Base dataset size (use redis-cli DBSIZE and MEMORY USAGE on a sample)
# + Replication output buffer: ~64MB per replica
# + AOF rewrite buffer: ~64MB during rewrites
# + Copy-on-write overhead during BGSAVE: up to 2x during heavy writes
# + Client output buffers: ~1KB per client
# + OS overhead: ~1-2GB
# Rule of thumb: maxmemory = 75% of available RAM
# Network bandwidth:
# Replication: write_throughput_bytes * num_replicas
# Client traffic: ops_per_sec * avg_response_size
# Full sync: dataset_size (one-time during replica bootstrap or failover)
# Example sizing for 20GB dataset, 100K ops/sec:
# RAM per node: 20GB data + 4GB buffers + 2GB OS = 26GB -> 32GB node (75% = 24GB maxmemory)
# CPU: 1 core handles ~100K ops/sec for simple commands (GET/SET)
# Network: 100K ops * 1KB avg = 100MB/s client + 50MB/s replication = 150MB/s per master
# Scaling decision tree:
# Need more read throughput? -> Add replicas (up to 5 per master)
# Need more write throughput? -> Redis Cluster (add shards)
# Need more memory? -> Redis Cluster (distribute dataset across shards)
# Need lower latency? -> Reduce network hops (co-locate, use unix sockets)
# Need global distribution? -> Multi-region replication or Redis Enterprise Active-ActiveГоризонтальное масштабирование с кластером Redis
# Add shards to an existing Redis Cluster
# 1. Start new Redis nodes
redis-server /etc/redis/new-master.conf
redis-server /etc/redis/new-replica.conf
# 2. Add the new master to the cluster
redis-cli --cluster add-node new-master:7000 existing-node:7000 -a password
# 3. Add the new replica to follow the new master
redis-cli --cluster add-node new-replica:7000 existing-node:7000 \
--cluster-slave --cluster-master-id NEW_MASTER_ID -a password
# 4. Reshard slots to the new master
redis-cli --cluster reshard existing-node:7000 \
--cluster-from all --cluster-to NEW_MASTER_ID \
--cluster-slots 4096 --cluster-yes -a password
# 5. Verify the new slot distribution
redis-cli -c -h existing-node -p 7000 -a password CLUSTER SLOTS
# Remove a shard (scale down)
# 1. Reshard all slots away from the node
redis-cli --cluster reshard existing-node:7000 \
--cluster-from REMOVING_NODE_ID --cluster-to TARGET_NODE_ID \
--cluster-slots 5461 --cluster-yes -a password
# 2. Remove the empty node
redis-cli --cluster del-node existing-node:7000 REMOVING_NODE_ID -a passwordРекомендации по вертикальному масштабированию
# When to scale vertically vs horizontally:
# Scale UP (bigger instances) when:
# - Dataset fits in single-node memory
# - Workload uses multi-key operations (MGET, SUNION, Lua across keys)
# - Operational simplicity is more important than cost efficiency
# - Using Redis modules that don't support Cluster mode well
# Scale OUT (more shards) when:
# - Dataset exceeds single-node memory
# - Write throughput exceeds single-thread capacity (~200K ops/sec)
# - You need per-shard isolation for multi-tenant workloads
# - Cost per GB of RAM is a concern (many smaller nodes vs few large ones)
# Cloud instance recommendations:
# AWS: cache.r7g.xlarge (4 vCPU, 26GB) to cache.r7g.16xlarge (64 vCPU, 419GB)
# Azure: P1 (6GB) to P5 (120GB) per shard
# GCP: 5GB to 300GB per instance (Memorystore Standard)
# Bare metal:
# CPU: 2-4 cores dedicated to Redis (single-threaded, but background tasks use extra cores)
# RAM: 32-128GB per node (NVMe for swap-as-last-resort)
# Network: 10Gbps minimum, 25Gbps for large datasets
# Storage: NVMe SSD for AOF/RDB persistence (IOPS matters for fsync)Заключение
Высокая доступность Redis — это не единственный выбор конфигурации — это комплексная система, охватывающая топологию репликации, обнаружение сбоев, автоматическое переключение при сбое, настройку клиента, стратегию сохранения, управление памятью, безопасность, мониторинг и эксплуатационные процедуры. Правильная архитектура высокой доступности зависит от ваших конкретных требований.
Для большинства приложенийRedis Sentinelс тремя экземплярами Sentinel, контролирующими главный сервер и две реплики, обеспечивает проверенное, проверенное в боевых условиях решение высокой доступности с автоматическим переключением при сбое менее чем за 30 секунд. Если вам необходимо горизонтальное масштабирование, превышающее пропускную способность или объем памяти одного главного устройства,Redis Clusterраспределяет набор данных по нескольким сегментам, сохраняя при этом встроенную функцию аварийного переключения для каждого сегмента. Для сред Kubernetes такие операторы, какSpotahomeиOpsTree, кодируют передовые методы работы в декларативных CRD, аRedis Enterpriseпредоставляет наиболее многофункциональный вариант с активной-активной георепликацией и поддержкой модулей.
Облачные службы —AWS ElastiCache,Azure Cache для RedisиGCP Memorystore— устраняют эксплуатационную нагрузку, связанную с запуском инфраструктуры Redis, но имеют меньшую гибкость и более высокие затраты при масштабировании. Для организаций с «голой» инфраструктуройk3s с Rancher и Longhornпредоставляет полностью открытую, независимую от облака альтернативу, которая обеспечивает высокую доступность корпоративного уровня без привязки к поставщику.
Альтернативы, такие какDragonflyиKeyDB, стоит оценить для конкретных случаев использования — Dragonfly для необработанной многопоточной пропускной способности на больших машинах и KeyDB для активно-активной репликации с несколькими хозяевами. Оба они совместимы с Redis и могут служить полной заменой во многих сценариях.
Независимо от того, какую архитектуру вы выберете, основные принципы работы остаются неизменными: настройте правильное сохранение (гибрид RDB + AOF), используйтеmin-replicas-to-writeдля предотвращения потери данных из-за разделения мозга, определите размер журнала невыполненной репликации для вашего тома записи, шифруйте весь трафик с помощью TLS, обеспечьте доступ с наименьшими привилегиями с помощью списков ACL, отслеживайте задержку репликации и использование памяти с помощью Prometheus и Grafana, резервное копирование снимков RDB на удаленное хранилище хранилище и, что наиболее важно, регулярно тестируйте аварийное переключение. Система аварийного переключения, которая никогда не тестировалась, — это система, которая не работает. Проводите ежемесячные тренировки по аварийному восстановлению, анализируйте сбои с помощью инструментов хаос-инжиниринга и измеряйте фактическое время восстановления. Уверенность, которую вы получаете в результате систематического тестирования, — это то, что отличает развертывание Redis, которое выдерживает производственные инциденты, от такого, которое превращает сбой сервера в отключение всей компании.