中间件-01-Redis集群与哨兵在测试中的验证点

在测试 Redis 时,第一反应通常是:

  • 服务能连上
  • key 能写进去
  • 主从节点看起来都在线
  • 执行一次主从切换,客户端也能恢复

这些动作只能说明“Redis 基本能用”,还远远不足以说明“Redis 在业务链路里可用”。

Redis 集群与哨兵最容易被测浅的地方,不在命令本身,而在下面这些真实问题:

  • 分片路由是否真的命中了预期节点
  • 主从复制是否存在延迟、断档和旧数据回放
  • 哨兵切换完成后,客户端连接池和业务重试是否真的跟上
  • 故障恢复后,拓扑、只读只写关系和监控是否一起收敛
  • 平台、应用和脚本观察到的“恢复成功”,是不是其实只覆盖了连通性

这篇文章只聚焦一个问题:

Redis Cluster 和 Redis Sentinel 在测试里,到底应该验证哪些点,怎样分层验证,怎样排查,才能把高可用和业务可用真正测实。

一、先把验证对象分层,别把 Redis 测试做成几条命令回放

Redis 集群与哨兵测试最常见的误区,是只围绕 PINGSETGET 和一次手工切换做验证。

更适合测试现场的做法,是把验证对象拆成下面五层:

1. 拓扑层

这一层回答的是:

  • 集群槽位是否分布正确
  • 主从关系是否符合预期
  • 哨兵是否都监控到了正确主节点
  • 故障后拓扑是否真正收敛

如果这层没有测清,后面看到的很多业务问题都容易被误判成“客户端偶发异常”。

2. 数据层

这一层关注:

  • 写入后能否被正确读取
  • 主从复制是否有延迟
  • 切换期间是否出现数据丢失、回退或旧值残留
  • 多 key 场景下是否出现跨槽问题

只测“能写能读”,但没测“什么时候读到旧值”,这会直接把问题留到线上。

3. 客户端层

这一层重点不是 Redis 自己,而是业务侧连接行为:

  • 客户端是否正确识别集群或哨兵模式
  • 连接池是否会缓存旧主节点
  • 重试、超时和熔断配置是否合理
  • MOVEDASKREADONLY 这类返回是否被正确处理

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. 验证动作

一个最小可执行流程通常可以这样组织:

  1. 执行基线读写校验
  2. 对固定 key 做连续写入和读取比对
  3. 注入单点故障或切换动作
  4. 持续记录客户端报错、目标节点变化和恢复时间
  5. 故障恢复后再次校验角色、复制和业务结果

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 自己看起来恢复了,但业务侧可能仍然在报:

  • READONLY
  • MOVED
  • NOAUTH
  • Connection reset

这些错误码决定的是修复方向,不记录就很容易误判。

4. 故障注入只停进程,不做网络层验证

真实现场里,很多异常不是节点彻底宕机,而是:

  • 主从网络抖动
  • 哨兵与主节点视图不一致
  • 客户端到旧主的连接未断干净

如果只做 kill 场景,很多恢复问题根本测不出来。

5. 恢复后不复核拓扑收敛

切换成功后如果没有复查:

  • 原主是否正确回归从节点
  • 复制链路是否恢复
  • 客户端是否全部切到新主

下次故障发生时,往往会出现更大的问题。

七、真实案例型段落:一次切换成功但业务仍持续报错的排查

场景

某测试平台把任务队列和结果缓存都放在 Redis Sentinel 后面。一次回归压测前,需要验证主节点异常后的自动切换能力。

执行

  • 先持续写入任务状态和结果摘要
  • 对主节点执行故障注入
  • 同时观察哨兵选主、应用日志和任务完成率

现象

  • 哨兵在十几秒内完成了主从切换
  • 新主已经晋升成功
  • 但测试平台在切换完成后仍持续报错近 2 分钟
  • 任务执行线程大量出现 READONLY 和连接重置

排查

排查顺序按下面四步推进:

  1. 先确认哨兵视图
    结果显示新主已经稳定,旧主已降级。

  2. 再确认 Redis 节点角色
    节点角色与复制关系都正常,没有继续抖动。

  3. 再看应用连接行为
    发现连接池仍缓存了旧主地址,部分长连接没有被主动淘汰。

  4. 最后核对应用重试策略
    发现任务写状态失败后会立即重试三次,短时间内把连接池错误放大。

修复

修复动作分成三步:

  • 调整客户端哨兵主节点刷新策略,缩短旧主缓存时间
  • 在切换异常场景下主动清理失效连接
  • 把高频写状态逻辑从“立即重试三次”改成“短退避 + 限次重试”

修复后再次执行同样场景,哨兵切换窗口仍然存在,但业务失败时间明显缩短,且不再出现切换完成后长时间持续报错。

八、Redis 测试结论应该怎么写,才有决策价值

Redis 集群与哨兵测试结束后,结论不建议只写“通过”或“切换正常”,更适合收成下面四类判断:

  • 拓扑是否稳定:槽位、主从关系、哨兵视图是否一致
  • 业务是否可用:切换期间失败窗口、旧值风险、重复写风险是否可接受
  • 客户端是否成熟:是否正确处理路由、角色变化和连接刷新
  • 恢复是否收敛:故障恢复后拓扑、监控、告警和连接状态是否一起回归正常

更有价值的结论通常长这样:

  • 切换本身成功,但客户端连接池刷新不及时,业务可用性仍不达标
  • 基础读写正常,但多 key 操作在 Cluster 模式下存在跨槽失败风险
  • 主从切换完成后拓扑能收敛,但恢复阶段监控和巡检项缺失,后续运维风险较高

Redis 真正值得测实的,不是“能不能切换”,而是切换、业务恢复、客户端收敛和后续二次故障准备是否一起成立。这才是 Redis 集群与哨兵在测试中的核心验证点。