中间件-01-Redis集群与哨兵在测试中的验证点
在测试 Redis 时,第一反应通常是:
- 服务能连上
- key 能写进去
- 主从节点看起来都在线
- 执行一次主从切换,客户端也能恢复
这些动作只能说明“Redis 基本能用”,还远远不足以说明“Redis 在业务链路里可用”。
Redis 集群与哨兵最容易被测浅的地方,不在命令本身,而在下面这些真实问题:
- 分片路由是否真的命中了预期节点
- 主从复制是否存在延迟、断档和旧数据回放
- 哨兵切换完成后,客户端连接池和业务重试是否真的跟上
- 故障恢复后,拓扑、只读只写关系和监控是否一起收敛
- 平台、应用和脚本观察到的“恢复成功”,是不是其实只覆盖了连通性
这篇文章只聚焦一个问题:
Redis Cluster 和 Redis Sentinel 在测试里,到底应该验证哪些点,怎样分层验证,怎样排查,才能把高可用和业务可用真正测实。
一、先把验证对象分层,别把 Redis 测试做成几条命令回放
Redis 集群与哨兵测试最常见的误区,是只围绕 PING、SET、GET 和一次手工切换做验证。
更适合测试现场的做法,是把验证对象拆成下面五层:
1. 拓扑层
这一层回答的是:
- 集群槽位是否分布正确
- 主从关系是否符合预期
- 哨兵是否都监控到了正确主节点
- 故障后拓扑是否真正收敛
如果这层没有测清,后面看到的很多业务问题都容易被误判成“客户端偶发异常”。
2. 数据层
这一层关注:
- 写入后能否被正确读取
- 主从复制是否有延迟
- 切换期间是否出现数据丢失、回退或旧值残留
- 多 key 场景下是否出现跨槽问题
只测“能写能读”,但没测“什么时候读到旧值”,这会直接把问题留到线上。
3. 客户端层
这一层重点不是 Redis 自己,而是业务侧连接行为:
- 客户端是否正确识别集群或哨兵模式
- 连接池是否会缓存旧主节点
- 重试、超时和熔断配置是否合理
MOVED、ASK、READONLY这类返回是否被正确处理
Redis 高可用很多时候不是坏在服务端,而是坏在客户端恢复链路不完整。
4. 故障切换层
这一层要回答:
- 节点异常后多久被识别
- 切换期间业务失败窗口有多大
- 切换完成后写流量是否真正切到新主
- 恢复后的旧主如何回到正确角色
如果只看“最终恢复”,却不看“切换窗口内业务损失”,这类测试结论通常没有决策价值。
5. 证据层
这一层决定排查效率,至少要收这些证据:
- Redis 节点状态和角色信息
- 集群槽位与哨兵主节点视图
- 客户端错误码、重试次数、连接目标
- 应用写失败、读旧值、超时的具体时间窗
- 切换前后关键监控点
没有证据层,测试就只能停留在“好像切过去了”。
二、Redis Cluster 和 Sentinel 的验证重点不一样,要分开设计
会把 Redis Cluster 和 Sentinel 混成一套验证模板,这通常会漏掉关键风险。
1. Cluster 更关注分片和路由正确性
Redis Cluster 的重点在:
- 槽位分布是否完整
- key 路由是否稳定
- 客户端是否支持重定向
- 分片节点异常后,业务是否只受部分槽位影响
适合优先验证的点包括:
cluster_state是否为ok- 所有槽位是否已分配
- 主从节点数量是否符合设计
- 热 key 是否过度集中在少数分片
- 多 key 操作是否存在跨槽失败
2. Sentinel 更关注主从切换和读写角色收敛
Redis Sentinel 的重点在:
- 主节点健康状态识别
- 哨兵法定人数是否足够
- 新主选举是否稳定
- 客户端是否能快速拿到新主
- 原主恢复后是否自动降级为从
适合优先验证的点包括:
- 哨兵对主节点的
down-after-milliseconds是否合理 - 主从切换窗口内写请求的失败比例
- 切换后读写是否仍打到旧主
- 恢复后的复制关系是否正常
如果系统同时用到了 Cluster 和 Sentinel,更应该把验证计划拆成两条链路,不建议只做一套“Redis 可用性测试”。
三、测试现场更实用的验证分层
Redis 集群与哨兵的验证,不建议一上来就做混合故障演练。更稳的方式是分成四个阶段。
1. 基线验证
先确认:
- 节点角色、拓扑、槽位、复制关系正常
- 应用连接参数与目标模式一致
- 基础读写、批量读写、热点读写都能完成
这一阶段不解决复杂问题,只负责确认环境是干净的。
2. 路由与复制验证
重点看:
- key 是否命中预期分片
- 主从复制延迟是否在接受范围内
- 读写分离场景下是否出现旧值
- 集群扩缩容后路由是否更新
这一阶段最容易发现“服务端没坏,但客户端缓存路由有问题”。
3. 故障切换验证
重点动作包括:
- 主节点停止服务
- 节点网络隔离
- 单个从节点故障
- 哨兵节点数量减少到临界值
这一阶段要记录的不是“有没有恢复”,而是:
- 发现故障用了多久
- 切换用了多久
- 业务失败窗口有多长
- 恢复后是否还有旧主残留写流量
4. 恢复收敛验证
做到切换成功就停了,但真正容易出问题的是恢复后:
- 原主恢复后角色是否正确
- 从节点是否重新挂回正确主节点
- 客户端连接池是否仍持有旧连接
- 监控、告警和治理脚本是否回到正常状态
这一阶段没补上,后续二次故障时很容易直接放大。
四、Redis 测试的最小执行骨架
下面这套骨架更适合测试平台、接口回归和环境巡检场景复用。
1. 执行前确认
先固定这些信息:
- 模式:
Cluster还是Sentinel - 业务读写路径:直连、代理、SDK 自动发现
- 验证 key 范围:普通 key、热点 key、事务 key、批量 key
- 目标时间窗:正常写入阶段、切换阶段、恢复阶段
2. 基线采样
至少记录:
- 节点角色和 IP
- 槽位分布或主从关系
- 客户端连接目标
- 当前监控关键值:ops、连接数、复制延迟、拒绝数
3. 验证动作
一个最小可执行流程通常可以这样组织:
- 执行基线读写校验
- 对固定 key 做连续写入和读取比对
- 注入单点故障或切换动作
- 持续记录客户端报错、目标节点变化和恢复时间
- 故障恢复后再次校验角色、复制和业务结果
4. 最小记录表
建议至少记录下面这些字段:
| 时间点 | 验证动作 | 客户端目标节点 | 返回结果 | 业务影响 | Redis 角色变化 | 备注 |
|---|---|---|---|---|---|---|
| 20:30:10 | 连续写入开始 | 10.0.0.11:6379 | 成功 | 无 | node-1 为主 | 基线 |
| 20:31:05 | 主节点断连 | 10.0.0.11:6379 | 超时 | 写失败 | 哨兵开始判定 | 切换中 |
| 20:31:18 | 重试写入 | 10.0.0.12:6379 | 成功 | 短暂抖动 | node-2 晋升为主 | 已切换 |
| 20:33:00 | 恢复校验 | 10.0.0.12:6379 | 成功 | 无 | node-1 降为从 | 收敛完成 |
这个表的价值不在格式,而在让测试结论能和时间线对齐。
五、不同场景下最值得先测的验证点
1. 接口自动化场景
重点看:
- 切换期间接口是否超时
- 是否出现写成功但读旧值
- 幂等接口是否被重试放大
- 缓存回源逻辑是否把 Redis 短抖动放大成应用故障
2. 测试平台场景
重点看:
- 任务调度、任务状态和结果回写是否依赖 Redis
- 切换时是否出现任务卡死、重复消费、状态错乱
- 连接池、订阅通道、延迟队列是否能一起恢复
3. 中间件巡检场景
重点看:
- 角色和拓扑是否漂移
- 复制延迟是否持续升高
- 哨兵是否出现视图不一致
- 告警是否只报节点宕机,却没报切换失败
六、Redis 集群与哨兵测试里最常见的坑
1. 节点在线不等于业务可用
很多测试把“端口通、INFO replication 正常”当成通过条件,但业务真正失败的地方常常是:
- 客户端还连着旧主
- 连接池没有及时刷新
- 应用重试把短故障放大成大量超时
2. 只测最终结果,不测切换窗口
如果结论只写“30 秒后恢复”,却没记录:
- 这 30 秒里失败了多少请求
- 是否出现旧值
- 是否有重复写入
那这次测试很难支撑发布判断。
3. 只看 Redis 状态,不看客户端错误类型
Redis 自己看起来恢复了,但业务侧可能仍然在报:
READONLYMOVEDNOAUTHConnection reset
这些错误码决定的是修复方向,不记录就很容易误判。
4. 故障注入只停进程,不做网络层验证
真实现场里,很多异常不是节点彻底宕机,而是:
- 主从网络抖动
- 哨兵与主节点视图不一致
- 客户端到旧主的连接未断干净
如果只做 kill 场景,很多恢复问题根本测不出来。
5. 恢复后不复核拓扑收敛
切换成功后如果没有复查:
- 原主是否正确回归从节点
- 复制链路是否恢复
- 客户端是否全部切到新主
下次故障发生时,往往会出现更大的问题。
七、真实案例型段落:一次切换成功但业务仍持续报错的排查
场景
某测试平台把任务队列和结果缓存都放在 Redis Sentinel 后面。一次回归压测前,需要验证主节点异常后的自动切换能力。
执行
- 先持续写入任务状态和结果摘要
- 对主节点执行故障注入
- 同时观察哨兵选主、应用日志和任务完成率
现象
- 哨兵在十几秒内完成了主从切换
- 新主已经晋升成功
- 但测试平台在切换完成后仍持续报错近 2 分钟
- 任务执行线程大量出现
READONLY和连接重置
排查
排查顺序按下面四步推进:
先确认哨兵视图
结果显示新主已经稳定,旧主已降级。再确认 Redis 节点角色
节点角色与复制关系都正常,没有继续抖动。再看应用连接行为
发现连接池仍缓存了旧主地址,部分长连接没有被主动淘汰。最后核对应用重试策略
发现任务写状态失败后会立即重试三次,短时间内把连接池错误放大。
修复
修复动作分成三步:
- 调整客户端哨兵主节点刷新策略,缩短旧主缓存时间
- 在切换异常场景下主动清理失效连接
- 把高频写状态逻辑从“立即重试三次”改成“短退避 + 限次重试”
修复后再次执行同样场景,哨兵切换窗口仍然存在,但业务失败时间明显缩短,且不再出现切换完成后长时间持续报错。
八、Redis 测试结论应该怎么写,才有决策价值
Redis 集群与哨兵测试结束后,结论不建议只写“通过”或“切换正常”,更适合收成下面四类判断:
- 拓扑是否稳定:槽位、主从关系、哨兵视图是否一致
- 业务是否可用:切换期间失败窗口、旧值风险、重复写风险是否可接受
- 客户端是否成熟:是否正确处理路由、角色变化和连接刷新
- 恢复是否收敛:故障恢复后拓扑、监控、告警和连接状态是否一起回归正常
更有价值的结论通常长这样:
- 切换本身成功,但客户端连接池刷新不及时,业务可用性仍不达标
- 基础读写正常,但多 key 操作在 Cluster 模式下存在跨槽失败风险
- 主从切换完成后拓扑能收敛,但恢复阶段监控和巡检项缺失,后续运维风险较高
Redis 真正值得测实的,不是“能不能切换”,而是切换、业务恢复、客户端收敛和后续二次故障准备是否一起成立。这才是 Redis 集群与哨兵在测试中的核心验证点。