Redis集群发生故障后到故障转移机制测试

Redis Cluster 是 Redis 的分布式解决方案,通过分片(sharding)将数据分散到多个节点,并利用主从复制和自动故障转移保证高可用性。当节点故障时,其读写流程会依赖集群的故障检测、自动故障转移机制动态调整,确保服务连续性。以下是具体流程及测试验证方法:

一、Redis Cluster 节点故障时的读写流程

Redis Cluster 中每个分片(slot)由一个主节点(master)负责读写,主节点有1个或多个从节点(slave)作为备份。节点故障分为主节点故障从节点故障,处理逻辑不同:

1. 故障检测:如何发现节点不可用?

集群中所有节点通过Gossip协议定期交换状态(默认每1秒发送PING消息,包含自身状态和已知节点的状态)。当节点A超过cluster-node-timeout(默认15秒)未收到节点B的PONG响应时,A会标记B为“疑似下线(PFAIL)”。

超过半数的主节点都标记某节点为PFAIL,则该节点被标记为“确定下线(FAIL)”,并通过Gossip协议广播给全集群,触发后续处理。

2. 从节点故障:对读写无直接影响

从节点仅作为主节点的备份,不处理读写请求(除非客户端显式指定从节点读)。若从节点故障:

  • 主节点会检测到从节点下线,但不影响分片的读写(主节点仍正常服务);
  • 集群会暂时失去该主节点的一个备份,若主节点后续故障,可能因无可用从节点导致分片不可用(需避免单从节点故障)。

3. 主节点故障:自动故障转移与读写切换

主节点故障是影响最大的场景,集群会自动触发故障转移(类似Redis Sentinel的逻辑),流程如下:

(1)从节点竞选新主节点

  • 故障主节点的所有从节点会竞选新主节点:通过Raft-like算法,从节点向集群中其他主节点发送投票请求,获得多数票(超过半数主节点支持)的从节点晋升为新主节点。

(2)更新集群状态

  • 新主节点会接管原主节点的所有slot,并通过Gossip协议广播“slot归属变更”;
  • 其他节点更新本地的“slot-节点映射表”,旧主节点被标记为FAIL。

(3)读写请求的路由调整

  • 故障转移前(主节点刚下线,未选出新主)
    客户端向原主节点发送读写请求时,会收到“CLUSTERDOWN Hash slot not served”错误(此时分片不可用)。

  • 故障转移中(新主节点正在竞选)
    客户端可能收到“MOVED”或“ASK”重定向消息(取决于节点是否已更新slot映射),客户端会根据重定向更新本地路由表,重试请求。

  • 故障转移后(新主节点接管slot)
    客户端通过更新后的路由表,直接向新主节点发送读写请求(读请求也可路由到新主节点的从节点,若开启readonly)。

4. 极端场景:无可用从节点的主节点故障

若故障主节点无从节点(或所有从节点也故障),则该主节点负责的slot会永久不可用,客户端访问这些slot时会持续收到“CLUSTERDOWN”错误,直到手动恢复节点。

二、测试Redis Cluster故障处理正确性的验证方法

验证需覆盖故障检测准确性故障转移完整性读写路由正确性数据一致性,需在隔离环境中模拟各类故障场景。

1. 测试环境准备

  • 部署Redis Cluster:至少3个主节点(每个主节点负责部分slot),每个主节点配置1个从节点(共6节点,满足多数投票条件);
  • 客户端工具:redis-cli(原生客户端)、自定义脚本(模拟并发读写,如Python的redis-py-cluster);
  • 监控工具:redis-cli cluster nodes(查看节点状态)、redis-cli cluster slots(查看slot归属)、redis-cli info replication(查看主从关系)。

2. 核心测试场景与验证步骤

场景1:主节点故障后的自动故障转移

测试目标:验证主节点故障后,从节点能否正确晋升为主节点,slot归属是否更新,读写是否恢复。

测试步骤

  1. 初始状态确认

    • 记录集群状态:redis-cli -h <主节点IP> cluster nodes,确认主节点A(如192.168.1.1:6379)及其从节点A-slave(192.168.1.2:6379),以及A负责的slot范围(如0-5460)。
    • 向A写入测试数据:redis-cli -c -h <A的IP> set slot_key "test_value"-c启用集群模式,自动处理重定向)。
  2. 模拟主节点故障

    • 强制终止主节点A的进程:ps -ef | grep redis-server | grep 6379 | awk '{print $2}' | xargs kill -9
  3. 观察故障转移过程

    • 每隔1秒执行redis-cli cluster nodes,观察A的状态变化(从“online”→“PFAIL”→“FAIL”),以及A-slave的状态(从“slave”→“master”)。
    • 记录故障转移耗时(从主节点故障到新主节点上线的时间,通常≤30秒)。
  4. 验证slot归属与读写

    • 执行redis-cli cluster slots,确认原A负责的slot(0-5460)已归属A-slave(新主节点)。
    • 读取数据:redis-cli -c -h <A-slave的IP> get slot_key,验证返回“test_value”(数据未丢失)。
    • 写入新数据:redis-cli -c -h <A-slave的IP> set new_key "new_value",验证写入成功,且其他节点可通过重定向访问。

预期结果

  • 主节点A被标记为FAIL,从节点A-slave晋升为新主,接管所有slot;
  • 故障转移后,原slot的读写请求可正常路由到新主节点,数据完整。

场景2:故障转移期间的客户端读写行为

测试目标:验证客户端在故障转移期间能否正确处理错误和重定向,最终恢复正常读写。

测试步骤

  1. 启动自定义客户端脚本:持续向主节点A的slot发送读写请求(每秒10次),记录请求结果(成功/失败/错误类型)。
  2. 模拟主节点A故障(同场景1步骤2),观察脚本日志:
    • 故障初期:是否出现“CLUSTERDOWN Hash slot not served”错误(分片不可用);
    • 故障转移中:是否收到“MOVED”重定向消息(客户端自动更新路由表);
    • 故障转移后:请求是否恢复成功(无错误)。

预期结果

  • 故障转移期间有短暂(通常10-30秒)的读写失败;
  • 客户端收到重定向后自动更新路由,故障转移完成后读写恢复正常,无数据丢失。

场景3:从节点故障对主节点的影响

测试目标:验证从节点故障后,主节点的读写是否不受影响,集群是否仍能正常服务。

测试步骤

  1. 确认主节点B及其从节点B-slave正常运行,B负责slot 5461-10922。
  2. 向B写入数据:set b_key "b_value",验证写入成功。
  3. 模拟B-slave故障:kill -9 <B-slave的PID>
  4. 验证主节点B状态:redis-cli -h <B的IP> info replication,确认B仍为“master”,且“connected_slaves”变为0。
  5. 向B执行读写操作:get b_key(应返回“b_value”)、set b_new "new"(应成功)。

预期结果

  • 从节点B-slave故障后,主节点B仍正常处理读写,集群无错误;
  • 若后续B故障,因无可用从节点,其负责的slot会不可用(验证此场景可进一步杀死B,观察是否返回CLUSTERDOWN)。

场景4:网络分区导致的“脑裂”防护

测试目标:验证网络分区时,集群能否避免双主节点(脑裂),保证数据一致性。

测试步骤

  1. 集群包含3主3从(主A、B、C;从A-slave、B-slave、C-slave),网络正常时A为某slot的主节点。
  2. 模拟网络分区:将主节点A与其他节点隔离(如iptables阻断A与B、C的通信),但A仍能接收客户端请求。
  3. 观察集群状态:
    • 分区外节点(B、C、A-slave等)会标记A为FAIL,A-slave晋升为新主;
    • 分区内的A因无法与多数节点通信,会降级为从节点(即使仍能接收请求,也会拒绝写入,返回“MOVED”)。
  4. 向分区内的A发送写入请求:set conflict_key "a",验证是否被拒绝(避免双写)。
  5. 恢复网络后,观察A是否同步新主节点的数据,成为其从节点。

预期结果

  • 网络分区时,仅分区外的新主节点(A-slave)可处理写入,分区内的原主A被降级,拒绝写入(无脑裂);
  • 网络恢复后,原主A同步新主数据,集群状态一致。

场景5:数据一致性验证(故障转移后)

测试目标:验证故障转移后,新主节点的数据与原主节点故障前的数据是否一致(无丢失/篡改)。

测试步骤

  1. 向主节点A写入大量数据(10万条,包含字符串、哈希等类型),记录数据指纹(如所有key的MD5总和:redis-cli --raw keys "*" | sort | xargs redis-cli mget | md5sum)。
  2. 杀死主节点A,等待从节点A-slave晋升为新主。
  3. 在新主节点A-slave上计算相同的数据指纹,与故障前对比。
  4. 随机抽查10%的key,验证value内容、过期时间等是否一致。

预期结果

  • 新主节点的数据指纹与原主节点完全一致,随机抽查的key内容无差异(从节点实时同步主节点数据,故障转移不丢失数据)。

三、测试工具与自动化

  • 故障注入:使用kill -9模拟进程崩溃,iptables模拟网络分区,dd填充磁盘模拟节点不可用;
  • 自动化脚本:用Python(redis-py-cluster)编写并发读写脚本,记录请求成功率、响应时间、错误类型;
  • 状态监控:定时执行cluster nodescluster slots,解析输出判断节点状态和slot归属是否正确;
  • 报告生成:汇总故障转移耗时、数据一致性结果、客户端错误率等指标,生成测试报告。

总结

Redis Cluster 节点故障时的核心保障是自动故障转移:主节点故障后,从节点通过竞选晋升为新主,接管slot并恢复读写;从节点故障不影响主节点服务。测试时需重点验证:故障检测准确性、故障转移完整性(新主接管slot)、客户端路由正确性(重定向处理)、数据一致性(无丢失)及极端场景(网络分区、无从节点)的容错能力。通过工具自动化和场景覆盖,可确保集群在故障时的高可用性。

posted @ 2025-08-01 20:09  程煕  阅读(64)  评论(0)    收藏  举报