背景与动机

2016 年,随着公司业务的快速发展,单机 Redis 已经无法满足我们对高可用性的要求。一次深夜的 Redis 宕机事故,导致核心服务不可用长达 20 分钟,那 20 分钟里,客服投诉电话此起彼伏,运维团队紧急排查问题,最终确认是 Redis 单点故障导致的。这次事故成为了推动我们部署 Redis 高可用架构的直接动力。

经过调研和评估,我们决定采用 Redis Sentinel(哨兵) 方案来实现主从自动故障转移。这篇博客记录的,就是那次企业级 Redis 高可用环境部署的完整过程,包括配置、测试和运维注意事项。

Redis高可用架构

Redis Sentinel 架构概述

Redis Sentinel 是 Redis 官方推荐的高可用性解决方案。它的核心功能包括:

  • 监控:Sentinel 会持续监控 Redis 主从节点是否正常工作。
  • 通知:当被监控的 Redis 节点出现问题时,Sentinel 可以通过 API 向管理员或其他应用程序发送通知。
  • 自动故障转移:当主节点不可用时,Sentinel 会发起故障转移,将从节点提升为新的主节点。
  • 配置提供者:客户端可以向 Sentinel 询问当前主节点的地址,Sentinel 会返回最新的信息。

为什么选择 Sentinel 而不是其他方案?

当时我们对比了三种方案:

  1. Redis Sentinel:官方方案,社区活跃,配置相对简单。
  2. Redis Cluster:官方分片方案,但当时还处于相对早期的阶段,运维复杂度较高。
  3. 第三方代理方案(如 Twemproxy、Codis):功能强大,但引入了额外的中间层,增加了系统复杂度。

最终选择 Sentinel 的原因是:我们的数据量还不需要分片,核心需求是高可用而非水平扩展,Sentinel 正好满足了这个需求。

环境规划

我们的部署环境涉及两台服务器:

角色 IP 地址 端口 说明
Master(主节点) 10.10.10.152 6386 Redis 主服务
Slave(从节点) 10.10.10.155 6387 Redis 从服务
Sentinel(哨兵) 10.10.10.155 26379 哨兵监控服务

Redis主从哨兵拓扑

哨兵配置文件详解

以下是 etc/redis/sentinel.conf 的完整配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# 监控名为 test1 的主节点,IP 为 10.10.10.152,端口为 6386
# 最后一个参数 1 表示至少有 1 个 Sentinel 同意才认为主节点下线
sentinel monitor test1 10.10.10.152 6386 1

# 主节点或从节点在 5000 毫秒内未响应,则判定为下线
sentinel down-after-milliseconds test1 5000

# 故障转移超时时间为 900000 毫秒(15 分钟)
# 如果在这个时间内未能完成故障转移,则认为失败
sentinel failover-timeout test1 900000

# 允许 Sentinel 对该主节点执行故障转移
sentinel can-failover test1 yes

# 故障转移后,同时向新的主节点发起同步的从节点数量
# 设置为 2 意味着允许 2 个从节点同时同步
sentinel parallel-syncs test1 2

# 配置纪元和领导纪元(Sentinel 内部用于选举和协调)
sentinel config-epoch test1 45
sentinel leader-epoch test1 45

# 已知的从节点信息
sentinel known-slave test1 10.10.10.155 6387

# Sentinel 自身监听的端口
port 26379

# Sentinel 工作目录
dir "/usr/local/etc"

# 当前纪元
sentinel current-epoch 45

关键参数解读

有几个参数在实际运维中特别重要,值得单独拿出来讲一讲:

down-after-milliseconds:这个参数决定了 Sentinel 认为一个节点”下线”的敏感程度。设置得太小(比如 1000ms),可能会因为网络抖动而产生误判;设置得太大(比如 30000ms),又会导致故障转移响应太慢。我们选择的 5000ms 是一个比较折中的值。

failover-timeout:这个参数控制了故障转移的最大等待时间。900000ms(15 分钟)看起来很长,但它的含义是:如果故障转移在这个时间内没有完成,Sentinel 会认为这次转移失败,并可能在之后重试。

parallel-syncs:这个参数控制了故障转移后,同时有多少个从节点可以向新的主节点发起数据同步。如果从节点数量很多,建议设置为一个较小的值(比如 1),以避免新的主节点在瞬间承受过大的同步压力。

部署步骤

第一步:启动哨兵服务

在 10.10.10.155 机器上执行以下命令启动哨兵服务:

1
redis-server /usr/local/etc/sentinel.conf --sentinel

哨兵端口 26379 实例启动,开始监控主从节点的状态。

第二步:确认主节点运行

在本机 10.10.10.152 上,确认主 Redis 服务正在运行:

1
sudo redis-server /etc/redis/redis_master_6386.conf

第三步:确认从节点运行

在其他机 10.10.10.155 上,确认从 Redis 服务正在运行:

1
sudo redis-server /etc/redis/redis_slave_6387.conf

第四步:配置主从复制

在 10.10.10.155 机器上进入 Redis 客户端,执行主从复制配置:

1
2
3
redis-cli -h 10.10.10.155 -p 6387
# 进入 Redis 后执行:
slaveof 10.10.10.152 6386

执行完毕后,本机(10.10.10.155)上的 Redis 实例就成为了主节点(10.10.10.152:6386)的从数据库。

Redis主从复制配置

第五步:验证主从状态

可以通过以下命令验证主从复制是否正常工作:

1
2
3
4
5
# 在主节点上
redis-cli -h 10.10.10.152 -p 6386 INFO replication

# 在从节点上
redis-cli -h 10.10.10.155 -p 6387 INFO replication

监控与告警测试

部署完成后,最关键的一步是验证整个高可用方案是否真的可靠。我们编写了一个 PHP 监控脚本 script_redis_monitor.php,用于检测 Redis 服务的状态并在异常时发送邮件告警。

测试要点

测试一:哨兵服务宕机告警

停掉哨兵服务(redis-server /usr/local/etc/sentinel.conf --sentinel 这个进程),然后运行 php script_redis_monitor.php 查看邮件报警。

注意:测试完成后记得重新启动哨兵服务。

测试二:Master 服务宕机告警

停掉 Master 服务(sudo redis-server /etc/redis/redis_master_6386.conf 这个进程),在 3 秒内 运行 php script_redis_monitor.php 查看邮件报警。

注意:3 秒这个时间窗口非常关键。因为 down-after-milliseconds 设置为 5000ms,如果在 Sentinel 检测到异常之前就运行了监控脚本,可能无法正确捕获故障状态。测试完成后记得重新启动 Master 服务。

测试三:Master 和 Slave 同时宕机

同时停掉 Master 服务(sudo redis-server /etc/redis/redis_master_6386.conf)和 Slave 服务(sudo redis-server /etc/redis/redis_slave_6387.conf),然后运行 php script_redis_monitor.php 查看邮件报警。

这个测试模拟了最极端的场景——整个 Redis 集群全部宕机。在这种情况下,告警系统必须能够及时通知运维人员介入处理。

Redis监控告警测试

运维经验与踩坑记录

在部署和运维 Redis Sentinel 的过程中,我们积累了不少经验教训:

1. 网络分区问题

Sentinel 依赖于节点间的网络通信来做决策。如果发生网络分区(比如机房之间的网络中断),可能会导致 Sentinel 无法正确判断节点状态。建议在部署时确保 Sentinel 节点与 Redis 节点之间的网络质量。

2. 脑裂风险

在极端情况下,如果网络分区导致部分 Sentinel 无法与主节点通信,可能会发生”脑裂”——两个主节点同时对外提供服务。通过合理配置 min-slaves-to-writemin-slaves-max-lag 参数,可以降低脑裂的风险。

3. 监控脚本的可靠性

我们最初使用的监控脚本存在一个 bug:批量检查时没有正确处理 access_token 的过期问题,导致在 Token 失效时误报大量告警。后来加入了 Token 刷新逻辑和重试机制,问题才得以解决。

4. 数据持久化的选择

Redis 提供了 RDB 和 AOF 两种持久化方式。在我们的场景中,选择了 AOF(appendonly yes),因为 AOF 的数据安全性更高,虽然性能略有损耗,但对于业务数据来说是可以接受的。

写在最后

这次 Redis Sentinel 的部署经历让我深刻地认识到:高可用不是一个工具或一项技术,而是一套体系。从架构设计、配置调优、监控告警到应急预案,每一个环节都不能掉以轻心。

如今回头看,Redis 生态已经更加丰富。Redis Cluster 已经成为生产环境的主流选择,云厂商也提供了托管的 Redis 高可用服务。但 Sentinel 所代表的高可用设计思想——持续监控、快速发现、自动恢复——依然是所有分布式系统都应该遵循的基本原则。