适用场景 & 前置条件

项目

要求

适用场景

QPS 1万+ 的缓存服务、会话存储、消息队列等需要高可用的场景

OS

RHEL/CentOS 8.5+ 或 Ubuntu 20.04+

内核

Linux Kernel 4.18+

Redis 版本

Redis 6.2+(推荐 7.0+,支持更好的 Sentinel 功能)

资源规格

最小:3节点 x 2C4G / 推荐:3节点 x 4C8G

网络

端口 6379(Redis)、26379(Sentinel)开放,节点间延迟 < 5ms

权限

root 或 sudo 权限,Redis 用户权限

技能要求

熟悉 Linux 命令、Redis 基础命令、网络基础


反模式警告(何时不适用)

⚠️ 以下场景不推荐使用本方案:

  1. 单机小流量场景:QPS < 1000,单实例足够,引入 Sentinel 反而增加复杂度

  2. 需要强一致性:Redis 主从复制是异步的,主节点宕机可能丢失数据,金融交易等场景不适用

  3. 已有 Redis Cluster:Redis Cluster 本身提供高可用和分片,无需 Sentinel

  4. 对延迟极度敏感:Sentinel 故障切换需要 15-30 秒,实时交易系统可能不满足

  5. 云环境托管 Redis:AWS ElastiCache、阿里云 Redis 已提供高可用,无需自建

替代方案对比:

场景

推荐方案

理由

大规模分片

Redis Cluster

自动分片、更好的扩展性

云环境

云厂商托管 Redis

免运维、SLA 保障

强一致性

关系型数据库 + 缓存

Redis 不适合强一致性场景

单机足够

Redis 主从(无 Sentinel)

简化架构


环境与版本矩阵

组件

RHEL/CentOS

Ubuntu/Debian

测试状态

OS 版本

RHEL 9.3 / CentOS Stream 9

Ubuntu 22.04 LTS

[已实测]

内核版本

5.14.0-362+

5.15.0-92+

[已实测]

Redis

6.2.14(repo)/ 7.2.4(编译)

6.0.16(apt)/ 7.2.4(编译)

[已实测]

最小规格

3节点 x 2C4G / 10GB SSD

3节点 x 2C4G / 10GB SSD

-

推荐规格

3节点 x 4C8G / 50GB SSD

3节点 x 4C8G / 50GB SSD

-

网络

千兆网卡,节点间延迟 < 5ms

千兆网卡,节点间延迟 < 5ms

-

版本差异说明:

  • Redis 6.2 vs 7.0:7.0 支持 ACL(访问控制列表)、更好的 Sentinel 性能

  • Redis 7.0 新增 SENTINEL CONFIG 命令,支持动态修改 Sentinel 配置

  • Ubuntu apt 源的 Redis 版本较旧,生产环境建议编译安装最新稳定版

阅读导航

📖 建议阅读路径:

快速上手(30分钟):→ 快速清单 → 实施步骤 Step 1-6 → 验证测试

深入理解(60分钟):→ 最小必要原理 → 实施步骤完整版 → 监控告警 → 最佳实践

故障排查:→ 常见故障与排错 → 调试思路 → FAQ


快速清单(Checklist)

准备阶段

  • 准备3台服务器(或虚拟机),配置网络互通

  • 检查系统版本与内核兼容性(uname -r

  • 安装 Redis 6.2+(redis-server --version

  • 配置防火墙开放 6379、26379 端口

实施阶段

  • 配置 Redis 主节点(/etc/redis/redis.conf

  • 配置 Redis 从节点(2个,指向主节点)

  • 配置 Sentinel 哨兵(3个,监控主节点)

  • 启动所有 Redis 和 Sentinel 服务

验证阶段

  • 测试主从复制(redis-cli -p 6379 INFO replication

  • 模拟主节点故障(kill -9 主节点 Redis 进程)

  • 验证自动故障切换(15-30秒内完成)

  • 验证数据一致性(从节点数据完整)

监控阶段

  • 配置 Prometheus 监控(Redis Exporter)

  • 配置告警规则(主从切换、复制延迟)

  • 配置 Grafana 面板

准备阶段

架构流程图

环境检查与 Redis 安装

目标: 在3台服务器上安装 Redis 并验证版本

RHEL/CentOS 命令:

# 检查系统版本
cat /etc/redhat-release
uname -r

# 安装 Redis(官方 repo)
yum install -y redis

# 配置最新版仓库源
vim /etc/yum.repos.d/redis.repo
[Redis]
name=Redis
baseurl=http://packages.redis.io/rpm/rockylinux8
enabled=1
gpgcheck=1
 
curl -fsSL https://packages.redis.io/gpg > /tmp/redis.key
sudo rpm --import /tmp/redis.key
sudo yum install redis

Ubuntu/Debian 命令:

# 检查系统版本
lsb_release -a
uname -r

# 安装 Redis
apt update
apt install -y redis-server

# 配置最新版仓库源
sudo apt-get update
sudo apt-get install lsb-release curl gpg
curl -fsSL https://packages.redis.io/gpg | sudo gpg --dearmor -o /usr/share/keyrings/redis-archive-keyring.gpg
sudo chmod 644 /usr/share/keyrings/redis-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/redis-archive-keyring.gpg] https://packages.redis.io/deb $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/redis.list
sudo apt-get update
sudo apt-get install redis

# 或使用 PPA 获取新版本(仅在Ubuntu下有效,不支持Debian)
add-apt-repository ppa:redislabs/redis
apt update && apt install -y redis-server

二进制包安装:

# 或编译安装最新版本(推荐生产环境)
# 安装编译插件
# centos
yum install -y gcc make tcl
# debian
apt install build-essential
# 获取最新版安装包
wget https://download.redis.io/redis-stable.tar.gz
tar -zxvf redis-stable.tar.gz && cd redis-stable
make && make install

# 安装到系统路径
cp src/redis-server /usr/local/bin/
cp src/redis-cli /usr/local/bin/
cp src/redis-sentinel /usr/local/bin/

# 创建配置目录
mkdir -p /etc/redis
mkdir -p /var/lib/redis
mkdir -p /var/log/redis
useradd -r -s /bin/false redis
chown -R redis:redis /var/lib/redis /var/log/redis

关键参数解释:

  1. 1. make 编译时会自动运行测试,确保二进制文件正确

  2. 2. /var/lib/redis:Redis 数据目录(RDB/AOF 文件存储位置)

  3. 3. useradd -r:创建系统用户(无登录权限),安全运行 Redis

执行前验证:

# 检查编译依赖
gcc --version
make --version
# 预期输出:gcc 8.x+ / make 4.x+

# 检查网络连通性(3台服务器互相测试)
ping -c 3 192.168.1.10  # 主节点
ping -c 3 192.168.1.11  # 从节点1
ping -c 3 192.168.1.12  # 从节点2

执行后验证:

# 检查 Redis 版本
redis-server --version
# 预期输出:Redis server v=7.2.4 [已实测]

# 检查文件权限
ls -ld /var/lib/redis /var/log/redis
# 预期输出:drwxr-xr-x redis redis

# 测试 Redis 启动
redis-server --port 9999 &
redis-cli -p 9999 PING
# 预期输出:PONG
redis-cli -p 9999 SHUTDOWN

常见错误示例:

# 错误1:编译失败
error: 'struct redisServer' has no member named 'xxx'
# 解决:更新 gcc 版本(yum install -y gcc-toolset-11)

# 错误2:权限不足
MISCONF Redis is configured to save RDB snapshots
# 解决:chown redis:redis /var/lib/redis

配置防火墙

RHEL/CentOS(firewalld):

# 开放 Redis 端口
firewall-cmd --permanent --add-port=6379/tcp
firewall-cmd --permanent --add-port=26379/tcp
firewall-cmd --reload

# 验证
firewall-cmd --list-ports
# 预期输出:6379/tcp 26379/tcp

Ubuntu/Debian(ufw):

# 开放端口
ufw allow 6379/tcp
ufw allow 26379/tcp
ufw reload

# 验证
ufw status
# 预期输出:6379/tcp ALLOW 26379/tcp ALLOW

iptables(通用):

# 开放端口
iptables -A INPUT -p tcp --dport 6379 -j ACCEPT
iptables -A INPUT -p tcp --dport 26379 -j ACCEPT

# 保存规则
iptables-save > /etc/iptables/rules.v4  # Debian/Ubuntu
service iptables save                    # RHEL/CentOS 7

实施阶段

配置 Redis 主节点

配置文件路径:/etc/redis/redis.conf(主节点:192.168.1.10)

完整配置示例(带逐行注释):

# 网络配置
bind 0.0.0.0                     # 监听所有网卡(生产环境建议指定 IP)
protected-mode no                # 关闭保护模式(建议配置密码后关闭)
port 6379                        # Redis 监听端口

# 通用配置
daemonize yes                    # 后台运行
pidfile /var/run/redis_6379.pid  # PID 文件位置
logfile /var/log/redis/redis.log # 日志文件
dir /var/lib/redis               # 数据目录
databases 16                     # 数据库数量(默认16个)

# 安全配置
requirepass YourStrongPassword123  # 设置密码(必需!)
masterauth YourStrongPassword123   # 主从复制密码(从节点需要)

# 持久化配置 - RDB
save 900 1                       # 900秒内至少1次写入则保存
save 300 10                      # 300秒内至少10次写入则保存
save 60 10000                    # 60秒内至少10000次写入则保存
stop-writes-on-bgsave-error yes  # RDB 失败时停止写入
rdbcompression yes               # RDB 压缩
rdbchecksum yes                  # RDB 校验和
dbfilename dump.rdb              # RDB 文件名

# 持久化配置 - AOF(推荐开启)
appendonly yes                   # 开启 AOF
appendfilename "appendonly.aof"  # AOF 文件名
appendfsync everysec             # 每秒同步(平衡性能与安全)
no-appendfsync-on-rewrite no     # rewrite 时不进行 fsync
auto-aof-rewrite-percentage 100  # AOF 文件增长100%时 rewrite
auto-aof-rewrite-min-size 64mb   # AOF 文件最小64MB时 rewrite

# 主从复制配置(主节点无需配置 replicaof)
replica-serve-stale-data yes     # 从节点断连时继续提供服务
replica-read-only yes            # 从节点只读
repl-diskless-sync no            # 使用磁盘同步(稳定)
repl-diskless-sync-delay 5       # 无盘同步延迟
repl-ping-replica-period 10      # 主节点 ping 从节点间隔
repl-timeout 60                  # 复制超时时间
repl-backlog-size 1mb            # 复制积压缓冲区大小
min-replicas-to-write 1          # 至少1个从节点在线才允许写入
min-replicas-max-lag 10          # 从节点最大延迟10秒

# 内存管理
maxmemory 2gb                    # 最大内存限制(根据服务器配置调整)
maxmemory-policy allkeys-lru     # 内存满时淘汰策略(LRU)

# 慢查询日志
slowlog-log-slower-than 10000    # 记录执行时间超过10ms的命令
slowlog-max-len 128              # 慢查询日志最大长度

# 客户端连接
maxclients 10000                 # 最大客户端连接数
timeout 300                      # 客户端空闲超时(秒)

关键参数解释:

  1. 1. min-replicas-to-write 1:至少1个从节点在线才允许写入,防止脑裂时数据丢失

  2. 2. appendfsync everysec:每秒刷盘一次,平衡性能与数据安全(最多丢失1秒数据)

  3. 3. maxmemory-policy allkeys-lru:内存满时使用 LRU 算法淘汰所有键(适合缓存场景)

执行前验证:

# 检查配置文件语法(Redis 7.0+)
redis-server /etc/redis/redis.conf --test-memory 1

# 确认端口未被占用
ss -tunlp | grep 6379
# 预期输出:无输出(端口未占用)

执行后验证:

# 启动 Redis
systemctl start redis
# 或手动启动:
redis-server /etc/redis/redis.conf

# 检查进程
ps -ef | grep redis-server
# 预期输出:redis xxx redis-server 0.0.0.0:6379

# 测试连接(需要密码)
redis-cli -h 192.168.1.10 -p 6379 -a YourStrongPassword123 PING
# 预期输出:PONG [已实测]

# 检查配置
redis-cli -h 192.168.1.10 -a YourStrongPassword123 CONFIG GET requirepass
# 预期输出:1) "requirepass" 2) "YourStrongPassword123"

# 写入测试数据
redis-cli -h 192.168.1.10 -a YourStrongPassword123 SET testkey "hello-redis"
redis-cli -h 192.168.1.10 -a YourStrongPassword123 GET testkey
# 预期输出:hello-redis

常见错误示例:

# 错误1:端口被占用
Could not create server TCP listening socket 0.0.0.0:6379: bind: Address already in use
# 解决:kill 占用端口的进程或修改端口

# 错误2:权限不足
Can't open the log file: Permission denied
# 解决:chown redis:redis /var/log/redis

# 错误3:密码认证失败
NOAUTH Authentication required
# 解决:redis-cli -a YourStrongPassword123

配置Redis从节点

从节点1(192.168.1.11)和从节点2(192.168.1.12)配置差异:

在主节点配置基础上,仅修改以下内容:

# 从节点配置差异
replicaof 192.168.1.10 6379      # 指定主节点 IP 和端口
masterauth YourStrongPassword123 # 主节点密码(必需)
replica-read-only yes            # 从节点只读(推荐)

# 可选:修改日志和 PID 文件名(避免冲突)
pidfile /var/run/redis_6379.pid
logfile /var/log/redis/redis.log

执行步骤(在从节点1和从节点2执行):

# 1. 复制主节点配置文件
scp root@192.168.1.10:/etc/redis/redis.conf /etc/redis/redis.conf

# 2. 修改配置文件
vim /etc/redis/redis.conf
# 添加:replicaof 192.168.1.10 6379

# 3. 启动 Redis
systemctl start redis

# 或手动启动
redis-server /etc/redis/redis.conf

执行后验证:

# 从节点检查复制状态
redis-cli -h 192.168.1.11 -a YourStrongPassword123 INFO replication
# 预期输出:
# role:slave
# master_host:192.168.1.10
# master_port:6379
# master_link_status:up
# master_sync_in_progress:0

# 从节点验证数据同步
redis-cli -h 192.168.1.11 -a YourStrongPassword123 GET testkey
# 预期输出:hello-redis [已实测]

# 主节点检查从节点连接
redis-cli -h 192.168.1.10 -a YourStrongPassword123 INFO replication
# 预期输出:
# role:master
# connected_slaves:2
# slave0:ip=192.168.1.11,port=6379,state=online,offset=xxx
# slave1:ip=192.168.1.12,port=6379,state=online,offset=xxx

常见错误示例:

# 错误1:主从连接失败
master_link_status:down
# 诊断命令:
redis-cli -h 192.168.1.11 -a YourStrongPassword123 INFO replication | grep master_link_down_since
# 解决:检查网络、防火墙、主节点密码

# 错误2:从节点数据不一致
# 诊断:检查复制偏移量
redis-cli -h 192.168.1.10 -a YourStrongPassword123 INFO replication | grep offset
redis-cli -h 192.168.1.11 -a YourStrongPassword123 INFO replication | grep offset
# 解决:等待同步完成或手动触发 REPLICAOF no one 再重新同步

配置Sentinel哨兵

Sentinel 配置文件路径:/etc/redis/sentinel.conf

完整配置示例(3个 Sentinel 节点相同配置):

# Sentinel 基础配置
port 26379                               # Sentinel 监听端口
daemonize yes                            # 后台运行
pidfile /var/run/redis-sentinel.pid      # PID 文件
logfile /var/log/redis/sentinel.log      # 日志文件
dir /var/lib/redis                       # 工作目录

# 监控主节点
sentinel monitor mymaster 192.168.1.10 6379 2   # 监控主节点,2票判定下线
sentinel auth-pass mymaster YourStrongPassword123  # 主节点密码
sentinel down-after-milliseconds mymaster 5000  # 5秒无响应判定主观下线
sentinel parallel-syncs mymaster 1              # 故障切换时同时同步的从节点数
sentinel failover-timeout mymaster 180000       # 故障切换超时(3分钟)

# 通知脚本(可选)
# sentinel notification-script mymaster /path/to/notify.sh
# sentinel client-reconfig-script mymaster /path/to/reconfig.sh

# Sentinel 自身保护
sentinel deny-scripts-reconfig yes       # 禁止通过 SENTINEL SET 修改脚本路径

关键参数解释:

  1. 1. sentinel monitor mymaster 192.168.1.10 6379 2

    • • mymaster:主节点名称(自定义)

    • • 192.168.1.10 6379:主节点地址

    • • 2:至少2个 Sentinel 认为主节点下线才触发故障切换(quorum)

  2. 2. down-after-milliseconds 5000:5秒无响应判定主观下线(SDOWN)

  3. 3. parallel-syncs 1:故障切换时,一次只有1个从节点向新主节点同步(减轻负载)

执行步骤(在3台服务器上都执行):

# 1. 创建 Sentinel 配置文件
cat > /etc/redis/sentinel.conf <<'EOF'
port 26379
daemonize yes
pidfile /var/run/redis-sentinel.pid
logfile /var/log/redis/sentinel.log
dir /var/lib/redis

sentinel monitor mymaster 192.168.1.10 6379 2
sentinel auth-pass mymaster YourStrongPassword123
sentinel down-after-milliseconds mymaster 5000
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 180000
sentinel deny-scripts-reconfig yes
EOF

# 2. 设置权限
chown redis:redis /etc/redis/sentinel.conf
chmod 640 /etc/redis/sentinel.conf

# 3. 启动 Sentinel
redis-sentinel /etc/redis/sentinel.conf

# 或使用 systemd(需创建 service 文件)
systemctl start redis-sentinel

systemd service 文件(/etc/systemd/system/redis-sentinel.service):

[Unit]
Description=Redis Sentinel
After=network.target

[Service]
Type=forking
User=redis
Group=redis
ExecStart=/usr/local/bin/redis-sentinel /etc/redis/sentinel.conf
ExecStop=/bin/kill -s TERM $MAINPID
PIDFile=/var/run/redis-sentinel.pid
Restart=always

[Install]
WantedBy=multi-user.target

执行后验证:

# 检查 Sentinel 进程
ps -ef | grep redis-sentinel
# 预期输出:redis-sentinel *:26379 [sentinel]

# 检查 Sentinel 状态
redis-cli -p 26379 SENTINEL masters
# 预期输出:
# 1) "name"
# 2) "mymaster"
# 3) "ip"
# 4) "192.168.1.10"
# 5) "port"
# 6) "6379"
# 7) "num-slaves"
# 8) "2"
# 9) "num-other-sentinels"
# 10) "2" [已实测]

# 检查 Sentinel 日志
tail -f /var/log/redis/sentinel.log
# 预期输出:+monitor master mymaster 192.168.1.10 6379 quorum 2

常见错误示例:

# 错误1:Sentinel 无法连接主节点
-sdown master mymaster 192.168.1.10 6379
# 解决:检查主节点是否在线、防火墙、密码配置

# 错误2:quorum 配置错误
No such master with specified name
# 解决:检查 sentinel monitor 配置中的主节点名称

# 错误3:配置文件权限错误
Permission denied
# 解决:chown redis:redis /etc/redis/sentinel.conf

验证阶段

场景: 模拟主节点故障,验证 Sentinel 自动切换

测试步骤:

# 1. 观察当前主节点
redis-cli -p 26379 SENTINEL get-master-addr-by-name mymaster
# 预期输出:192.168.1.10 6379

# 2. 在主节点上模拟故障(kill Redis 进程)
ssh root@192.168.1.10 "kill -9 \$(pgrep redis-server)"

# 3. 观察 Sentinel 日志(3台 Sentinel 都会记录)
tail -f /var/log/redis/sentinel.log
# 预期输出(关键步骤):
# +sdown master mymaster 192.168.1.10 6379      # 主观下线
# +odown master mymaster 192.168.1.10 6379      # 客观下线(2个 Sentinel 确认)
# +vote-for-leader xxx                          # 选举 Leader Sentinel
# +failover-state-select-slave                  # 选择新主节点
# +selected-slave slave 192.168.1.11:6379       # 选中从节点1
# +failover-state-send-slaveof-noone            # 提升为主节点
# +failover-end master mymaster 192.168.1.11 6379  # 故障切换完成
# +switch-master mymaster 192.168.1.10 6379 192.168.1.11 6379

# 4. 验证新主节点
redis-cli -p 26379 SENTINEL get-master-addr-by-name mymaster
# 预期输出:192.168.1.11 6379 [已实测]

# 5. 验证从节点指向
redis-cli -h 192.168.1.12 -a YourStrongPassword123 INFO replication
# 预期输出:
# role:slave
# master_host:192.168.1.11
# master_port:6379

# 6. 验证数据一致性
redis-cli -h 192.168.1.11 -a YourStrongPassword123 GET testkey
redis-cli -h 192.168.1.12 -a YourStrongPassword123 GET testkey
# 预期输出:hello-redis

# 7. 恢复原主节点(自动变为从节点)
ssh root@192.168.1.10 "redis-server /etc/redis/redis.conf"

# 等待10秒后检查
redis-cli -h 192.168.1.10 -a YourStrongPassword123 INFO replication
# 预期输出:
# role:slave
# master_host:192.168.1.11
# master_port:6379

故障切换时间测试:

# 脚本:持续写入数据,记录切换期间的失败次数
#!/bin/bash
REDIS_PASS="YourStrongPassword123"
FAIL_COUNT=0
SUCCESS_COUNT=0

whiletrue; do
    TIMESTAMP=$(date +"%Y-%m-%d %H:%M:%S.%3N")
# 通过 Sentinel 获取当前主节点
    MASTER=$(redis-cli -p 26379 SENTINEL get-master-addr-by-name mymaster | head -1)

# 写入测试
if redis-cli -h $MASTER -a $REDIS_PASS SET test_failover "$TIMESTAMP" > /dev/null 2>&1; then
echo"$TIMESTAMP - SUCCESS (Master: $MASTER)"
        ((SUCCESS_COUNT++))
else
echo"$TIMESTAMP - FAILED (Master: $MASTER)"
        ((FAIL_COUNT++))
fi

sleep 0.5
done

# 运行结果(手动 kill 主节点):
# 2025-01-15 10:00:00.000 - SUCCESS (Master: 192.168.1.10)
# 2025-01-15 10:00:00.500 - SUCCESS (Master: 192.168.1.10)
# ... kill 主节点 ...
# 2025-01-15 10:00:15.000 - FAILED (Master: 192.168.1.10)
# 2025-01-15 10:00:15.500 - FAILED (Master: 192.168.1.10)
# ... 15-30秒后 ...
# 2025-01-15 10:00:30.000 - SUCCESS (Master: 192.168.1.11)
#
# 统计:失败请求约 30-60 次(15-30秒 / 0.5秒间隔)

监控阶段

监控指标

Redis 原生监控命令:

# 主从复制状态
redis-cli -h 192.168.1.10 -a YourStrongPassword123 INFO replication

# Sentinel 状态
redis-cli -p 26379 SENTINEL masters
redis-cli -p 26379 SENTINEL slaves mymaster
redis-cli -p 26379 SENTINEL sentinels mymaster

# 性能指标
redis-cli -h 192.168.1.10 -a YourStrongPassword123 INFO stats
# 关键指标:
# instantaneous_ops_per_sec: QPS
# used_memory_human: 内存使用
# connected_clients: 客户端连接数
# keyspace_hits/keyspace_misses: 缓存命中率

Prometheus + Redis Exporter:

# 安装 Redis Exporter
wget https://github.com/oliver006/redis_exporter/releases/download/v1.55.0/redis_exporter-v1.55.0.linux-amd64.tar.gz
tar -zxvf redis_exporter-v1.55.0.linux-amd64.tar.gz
cp redis_exporter /usr/local/bin/

# 启动 Exporter(监控主节点)
redis_exporter \
  --redis.addr=192.168.1.10:6379 \
  --redis.password=YourStrongPassword123 \
  --web.listen-address=:9121 &

# Prometheus 配置
cat >> /etc/prometheus/prometheus.yml <<EOF
  - job_name: 'redis'
    static_configs:
      - targets: ['192.168.1.10:9121', '192.168.1.11:9121', '192.168.1.12:9121']
EOF

systemctl restart prometheus

关键 Prometheus 指标:

# Redis 可用性
up{job="redis"}

# QPS
rate(redis_commands_processed_total[1m])

# 内存使用率
redis_memory_used_bytes / redis_memory_max_bytes * 100

# 主从复制延迟
redis_master_repl_offset - redis_slave_repl_offset

# 缓存命中率
rate(redis_keyspace_hits_total[5m]) / (rate(redis_keyspace_hits_total[5m]) + rate(redis_keyspace_misses_total[5m])) * 100

# 连接数
redis_connected_clients

Prometheus 告警规则:

groups:
-name:redis_alerts
interval:30s
rules:
# 告警1:Redis 实例下线
-alert:RedisDown
expr:up{job="redis"}==0
for:1m
labels:
severity:critical
annotations:
summary:"Redis 实例下线 ({{ $labels.instance }})"
description:"Redis 实例 {{ $labels.instance }} 已下线超过 1 分钟"

# 告警2:主从复制延迟过大
-alert:RedisReplicationLag
expr:(redis_master_repl_offset-redis_slave_repl_offset)>1000
for:5m
labels:
severity:warning
annotations:
summary:"Redis 主从复制延迟 ({{ $labels.instance }})"
description:"从节点 {{ $labels.instance }} 延迟 {{ $value }} 字节"

# 告警3:内存使用率过高
-alert:RedisMemoryHigh
expr:(redis_memory_used_bytes/redis_memory_max_bytes*100)>90
for:5m
labels:
severity:warning
annotations:
summary:"Redis 内存使用率过高 ({{ $labels.instance }})"
description:"实例 {{ $labels.instance }} 内存使用率 {{ $value }}%"

# 告警4:缓存命中率过低
-alert:RedisCacheHitRateLow
expr:rate(redis_keyspace_hits_total[5m])/(rate(redis_keyspace_hits_total[5m])+rate(redis_keyspace_misses_total[5m]))*100<80
for:10m
labels:
severity:warning
annotations:
summary:"Redis 缓存命中率过低 ({{ $labels.instance }})"
description:"实例 {{ $labels.instance }} 缓存命中率 {{ $value }}%"

# 告警5:连接数过多
-alert:RedisConnectionsHigh
expr:redis_connected_clients>8000
for:5m
labels:
severity:warning
annotations:
summary:"Redis 连接数过多 ({{ $labels.instance }})"
description:"实例 {{ $labels.instance }} 连接数 {{ $value }}"

Grafana 面板推荐:

  • 官方面板 ID:763(Redis Dashboard for Prometheus Redis Exporter)

  • 导入方法:Grafana → Dashboards → Import → 输入 763

最小必要原理

核心机制:

Redis Sentinel 是 Redis 官方提供的高可用解决方案,通过多个 Sentinel 节点监控 Redis 主从集群,在主节点故障时自动选举新主节点并重新配置从节点。

工作流程:

  1. 监控(Monitoring):Sentinel 每秒 PING 主从节点和其他 Sentinel

  2. 主观下线(SDOWN):单个 Sentinel 认为节点下线(超过 down-after-milliseconds

  3. 客观下线(ODOWN):多个 Sentinel(达到 quorum)认为主节点下线

  4. 选举 Leader:Sentinel 之间协商选举一个 Leader 执行故障切换

  5. 故障切换

    • 从从节点中选择新主节点(优先级、复制偏移量、runid)

    • 向新主节点发送 SLAVEOF NO ONE

    • 其他从节点执行 SLAVEOF 新主节点

    • 更新 Sentinel 配置文件

为什么需要3个 Sentinel?

  • 防止脑裂:quorum=2 时,至少2个 Sentinel 确认主节点下线才触发切换

  • 高可用:1个 Sentinel 故障不影响监控和切换

  • 奇数原则:3个节点避免选举平票(2个节点可能同时认为对方下线)

为什么切换时间是 15-30 秒?

  •  down-after-milliseconds 5000:5秒判定主观下线

  • Sentinel 协商 + 选举 Leader:5-10秒

  • 选择新主节点 + 重新配置从节点:5-10秒

  • 总计:15-30秒

数据丢失风险:

  • Redis 主从复制是异步的,主节点写入后立即返回,不等待从节点确认

  • 主节点宕机前,部分数据可能未同步到从节点,导致丢失最多几秒的数据

  • 通过 min-replicas-to-write 1 减少风险(至少1个从节点在线才允许写入)

性能基准测试

redis-benchmark 工具:

# 测试 SET 性能(10万请求,50并发)
redis-benchmark -h 192.168.1.10 -p 6379 -a YourStrongPassword123 \
  -t set -n 100000 -c 50 -d 1024

# 预期输出(参考值,实际取决于硬件):
# SET: 50000.00 requests per second
# Latency avg: 1.00ms
# Latency p99: 3.50ms

# 测试 GET 性能
redis-benchmark -h 192.168.1.10 -a YourStrongPassword123 \
  -t get -n 100000 -c 50 -d 1024

# 预期输出:
# GET: 60000.00 requests per second

# 综合测试(所有命令)
redis-benchmark -h 192.168.1.10 -a YourStrongPassword123 \
  -n 100000 -c 50 -q

调优参数:

# Redis 配置优化
tcp-backlog 511                  # TCP 连接队列(需匹配系统 net.core.somaxconn)
tcp-keepalive 300                # TCP keepalive 间隔
timeout 0                        # 关闭客户端空闲超时(长连接场景)
maxclients 10000                 # 最大客户端连接数

# 系统内核参数优化(/etc/sysctl.conf)
net.core.somaxconn = 511# TCP 连接队列
net.ipv4.tcp_max_syn_backlog = 511
vm.overcommit_memory = 1# 允许内存过度分配(Redis fork 需要)

常见故障与排错

症状

诊断命令

可能根因

快速修复

永久修复

主从复制中断

INFO replication | grep master_link_status

1. 网络中断
2. 主节点密码错误
3. 主节点宕机

REPLICAOF 主节点IP 端口

检查网络、防火墙、密码配置

Sentinel 无法切换

SENTINEL masters

1. quorum 配置错误
2. Sentinel 数量不足
3. 所有从节点都下线

修正 quorum 配置
启动更多 Sentinel

确保至少3个 Sentinel
检查从节点状态

主从数据不一致

比对 INFO replication 的 master_repl_offset

1. 复制延迟
2. 主节点 AOF 损坏
3. 从节点未同步完成

等待同步完成
或手动 REPLICAOF no one 重新同步

优化网络
增加 repl-backlog-size

频繁触发故障切换

查看 Sentinel 日志

1. down-after-milliseconds 设置过小
2. 网络抖动
3. 主节点负载过高

增加 down-after-milliseconds 到 10000

优化 Redis 性能
升级网络设备

故障切换后无法写入

INFO replication

1. 新主节点配置了 replica-read-only yes
2. Sentinel 未更新客户端配置

CONFIG SET replica-read-only no

确保客户端通过 Sentinel 发现主节点

从节点延迟过大

redis-cli LATENCY DOCTOR

1. 主节点写入过快
2. 从节点硬盘慢
3. 网络带宽不足

暂停部分写入
增加 repl-backlog-size

升级从节点硬件
使用 SSD

调试思路(系统性排查)

诊断命令集合:

# 1. 检查 Redis 主从状态
redis-cli -h 192.168.1.10 -a YourStrongPassword123 INFO replication
redis-cli -h 192.168.1.11 -a YourStrongPassword123 INFO replication

# 2. 检查 Sentinel 监控状态
redis-cli -p 26379 SENTINEL masters
redis-cli -p 26379 SENTINEL slaves mymaster

# 3. 检查网络连通性
ping -c 3 192.168.1.10
telnet 192.168.1.10 6379
telnet 192.168.1.10 26379

# 4. 检查防火墙
iptables -L -n | grep -E "6379|26379"
firewall-cmd --list-ports

# 5. 检查 Redis 日志
tail -f /var/log/redis/redis.log
# 关键错误:
# Connection refused
# Authentication failed
# MISCONF

# 6. 检查 Sentinel 日志
tail -f /var/log/redis/sentinel.log
# 关键事件:
# +sdown(主观下线)
# +odown(客观下线)
# +failover-end(切换完成)

# 7. 手动触发故障切换(测试用)
redis-cli -p 26379 SENTINEL failover mymaster

# 8. 检查复制延迟
redis-cli -h 192.168.1.10 -a YourStrongPassword123 INFO replication | grep master_repl_offset
redis-cli -h 192.168.1.11 -a YourStrongPassword123 INFO replication | grep slave_repl_offset

# 9. 查看慢查询日志
redis-cli -h 192.168.1.10 -a YourStrongPassword123 SLOWLOG GET 10

变更与回滚剧本

灰度策略

场景: 需要升级 Redis 版本或修改配置

步骤:

# 1. 选择低峰期维护窗口(凌晨 2-4 点)

# 2. 先在从节点1升级
ssh root@192.168.1.11
systemctl stop redis
# 升级 Redis(编译或替换二进制文件)
redis-server --version  # 验证新版本
# 更新配置文件(如需要)
systemctl start redis
redis-cli -h 192.168.1.11 -a YourStrongPassword123 INFO replication
# 验证:role:slave, master_link_status:up

# 3. 观察10分钟,确认从节点1正常

# 4. 在从节点2升级(同上)

# 5. 手动触发故障切换,将从节点1提升为主节点
redis-cli -p 26379 SENTINEL failover mymaster
# 等待15-30秒

# 6. 验证新主节点
redis-cli -p 26379 SENTINEL get-master-addr-by-name mymaster
# 预期输出:192.168.1.11 6379

# 7. 升级原主节点(此时已变为从节点)
ssh root@192.168.1.10
systemctl stop redis
# 升级...
systemctl start redis

# 8. 验证所有节点版本一致
redis-cli -h 192.168.1.10 -a YourStrongPassword123 INFO server | grep redis_version
redis-cli -h 192.168.1.11 -a YourStrongPassword123 INFO server | grep redis_version
redis-cli -h 192.168.1.12 -a YourStrongPassword123 INFO server | grep redis_version

回滚条件与命令

回滚触发条件:

  1. 1. 升级后主从复制中断超过 5 分钟

  2. 2. 新版本出现稳定性问题(频繁崩溃)

  3. 3. 性能下降超过 30%

回滚步骤:

# 1. 停止所有 Redis 和 Sentinel
ssh root@192.168.1.10 "systemctl stop redis redis-sentinel"
ssh root@192.168.1.11 "systemctl stop redis redis-sentinel"
ssh root@192.168.1.12 "systemctl stop redis redis-sentinel"

# 2. 恢复旧版本二进制文件
ssh root@192.168.1.10 "cp /backup/redis-server.bak /usr/local/bin/redis-server"
# ... 在所有节点执行

# 3. 恢复配置文件
ssh root@192.168.1.10 "cp /backup/redis.conf.bak /etc/redis/redis.conf"
ssh root@192.168.1.10 "cp /backup/sentinel.conf.bak /etc/redis/sentinel.conf"

# 4. 启动服务
ssh root@192.168.1.10 "systemctl start redis redis-sentinel"
# ... 在所有节点执行

# 5. 验证回滚结果
redis-cli -h 192.168.1.10 -a YourStrongPassword123 INFO server | grep redis_version
redis-cli -p 26379 SENTINEL masters

数据备份与恢复

自动化备份脚本:

#!/bin/bash
# 路径:/opt/scripts/backup_redis.sh

BACKUP_DIR="/backup/redis/$(date +%Y%m%d_%H%M%S)"
mkdir -p ${BACKUP_DIR}

# 1. 触发 RDB 快照
redis-cli -h 192.168.1.10 -a YourStrongPassword123 BGSAVE

# 2. 等待快照完成
while [ $(redis-cli -h 192.168.1.10 -a YourStrongPassword123 LASTSAVE) -eq $LAST_SAVE ]; do
sleep 1
done

# 3. 备份 RDB 和 AOF 文件
cp /var/lib/redis/dump.rdb ${BACKUP_DIR}/
cp /var/lib/redis/appendonly.aof ${BACKUP_DIR}/

# 4. 备份配置文件
cp /etc/redis/redis.conf ${BACKUP_DIR}/
cp /etc/redis/sentinel.conf ${BACKUP_DIR}/

# 5. 备份元数据
echo"Backup Time: $(date)" > ${BACKUP_DIR}/metadata.txt
redis-cli -h 192.168.1.10 -a YourStrongPassword123 INFO server >> ${BACKUP_DIR}/metadata.txt

# 6. 压缩备份
tar -czf ${BACKUP_DIR}.tar.gz -C ${BACKUP_DIR} .
rm -rf ${BACKUP_DIR}

# 7. 保留最近7天备份
find /backup/redis -type f -mtime +7 -delete

# 定时任务(每天凌晨2点备份)
# crontab -e
# 0 2 * * * /opt/scripts/backup_redis.sh

数据恢复步骤:

# 1. 停止 Redis
systemctl stop redis

# 2. 恢复备份文件
tar -xzf /backup/redis/20250115_020000.tar.gz -C /tmp
cp /tmp/dump.rdb /var/lib/redis/
cp /tmp/appendonly.aof /var/lib/redis/
chown redis:redis /var/lib/redis/*

# 3. 启动 Redis
systemctl start redis

# 4. 验证数据
redis-cli -h 192.168.1.10 -a YourStrongPassword123 DBSIZE
# 预期输出:与备份时一致

最佳实践

  • 1. 使用密码认证(必需)

    requirepass YourStrongPassword123
    masterauth YourStrongPassword123
    
  • 2. 开启持久化(AOF + RDB)

    appendonly yes
    appendfsync everysec
    save 900 1
    save 300 10
    save 60 10000
    
  • 3. 配置主从复制保护

    min-replicas-to-write 1      # 至少1个从节点在线
    min-replicas-max-lag 10      # 从节点最大延迟10秒
    
  • 4. Sentinel quorum 配置

  • 3个 Sentinel:quorum=2

  • 5个 Sentinel:quorum=3

  • 公式:quorum = floor(Sentinel数量 / 2) + 1

  • 5. 监控关键指标

  • 主从复制延迟:master_repl_offset - slave_repl_offset < 100

  • 缓存命中率:> 80%

  • 内存使用率:< 80%

  • 连接数:< maxclients * 0.8

  • 6. 定期故障演练(每季度一次)

  • 测试主节点宕机场景

  • 测试所有从节点宕机场景

  • 测试网络分区(脑裂)场景

  • 7. 客户端连接方式

    # Python 示例(使用 redis-py-sentinel)
    from redis.sentinel import Sentinel
    
    sentinel = Sentinel([
        ('192.168.1.10', 26379),
        ('192.168.1.11', 26379),
        ('192.168.1.12', 26379)
    ], socket_timeout=0.1)
    
    # 自动发现主节点
    master = sentinel.master_for('mymaster',
        password='YourStrongPassword123',
        socket_timeout=0.1)
    
    # 写入
    master.set('key', 'value')
    
    # 从从节点读取(可选)
    slave = sentinel.slave_for('mymaster',
        password='YourStrongPassword123',
        socket_timeout=0.1)
    value = slave.get('key')
    
  • 8. 避免大 key

  • 单个 String:< 10MB

  • 单个 List/Set/Hash:< 10000 元素

  • 使用 redis-cli --bigkeys 检测大 key

  • 9. 设置合理的内存淘汰策略

    maxmemory 2gb
    maxmemory-policy allkeys-lru  # 缓存场景
    # 或 volatile-lru(仅淘汰设置过期时间的key)
    
  • 10. 定期清理过期 key

  • 使用 EXPIRE 设置过期时间

  • 监控 expired_keys 指标

  • 避免大量 key 同时过期(分散过期时间)

FAQ

Q1: Redis Sentinel 和 Redis Cluster 的区别?A: Sentinel 提供主从高可用,无分片功能;Cluster 提供分片 + 高可用,适合大规模数据。单机几十 GB 数据用 Sentinel,超过 100GB 建议 Cluster。

Q2: Sentinel 最少需要几个节点?A: 最少3个。2个 Sentinel 无法达成 quorum(需要2票,但只有2个节点),1个 Sentinel 故障后无法切换。

Q3: 故障切换会丢失数据吗?A: 会。Redis 主从复制是异步的,主节点宕机前未同步到从节点的数据会丢失(通常几秒内的数据)。

Q4: 如何减少数据丢失?A:

  1. 1. 配置 min-replicas-to-write 1:至少1个从节点在线才允许写入

  2. 2. 开启 AOF:appendfsync everysec(最多丢失1秒数据)

  3. 3. 使用 WAIT 命令:WAIT 1 1000(等待至少1个从节点确认,超时1秒)

Q5: Sentinel 故障切换为什么需要 15-30 秒?A: 包含主观下线判定(5秒)、客观下线协商(5-10秒)、选举 Leader(5秒)、重新配置从节点(5-10秒)。可通过减少 down-after-milliseconds 加快,但可能误切换。

Q6: 可以在同一台服务器上运行 Redis 和 Sentinel 吗?A: 可以,但不推荐生产环境。服务器宕机会同时失去 Redis 和 Sentinel,降低可用性。

Q7: 主节点恢复后会自动变回主节点吗?A: 不会。原主节点恢复后自动变为从节点。如需切回,手动执行 SENTINEL failover mymaster

Q8: 如何监控 Sentinel 本身的健康状态?A:

  • • redis-cli -p 26379 PING:检查 Sentinel 是否响应

  • • redis-cli -p 26379 SENTINEL ckquorum mymaster:检查 quorum 是否满足

  • • Prometheus redis_sentinel_master_status 指标

Q9: 客户端如何连接 Sentinel?A: 不直接连接 Redis,而是通过 Sentinel API 获取当前主节点地址。大多数 Redis 客户端库(如 redis-py、Jedis)都支持 Sentinel。

Q10: 支持多个主节点吗?A: 可以。一组 Sentinel 可以监控多个 Redis 主从集群,配置多个 sentinel monitor 即可。但每组主从集群是独立的(无分片)。


扩展阅读

官方文档:

  • Redis Sentinel 官方文档:https://redis.io/docs/management/sentinel/

  • Redis 主从复制:https://redis.io/docs/management/replication/

  • Redis 持久化:https://redis.io/docs/management/persistence/

深入技术博客:

  • Redis Sentinel 源码解析:https://github.com/redis/redis/tree/unstable/src

  • 高可用架构设计:https://www.redisconf.com/

社区资源:

  • Redis 中文社区:https://redis.com.cn/

  • Stack Overflow Redis 标签:https://stackoverflow.com/questions/tagged/redis

  • Reddit /r/redis:https://reddit.com/r/redis

参考连接:

https://mp.weixin.qq.com/s/QXEWJuIJTBU_gbU_xUWuCA