验证MySQL主从切换后的数据一致性是数据库可靠性测试的核心场景

一、测试设计核心思路

  1. 模拟真实场景
    • 区分计划内切换(运维手动切换)和故障切换(主库宕机、网络分区)。
    • 覆盖不同负载:空闲状态、高并发读写、大事务执行中切换。
  2. 数据可追踪
    • 生成可验证的唯一数据(如全局ID、哈希值),确保每条数据可溯源。
  3. 验证维度全面
    • 数据完整性:数据是否丢失
    • 数据正确性:主从数据是否完全一致
    • 复制延迟:切换后新主库是否包含旧主库崩溃前的最后事务
    • 业务连续性:应用能否无感知重连新主库

二、具体测试用例设计

场景1:基础数据一致性验证

测试步骤 预期结果
1. 主库插入1000条带唯一ID的数据(如INSERT ... VALUES (uuid, ...) 数据实时同步到从库
2. 触发切换(手动或模拟主库宕机) 从库提升为新主库,切换时间 ≤ RTO(如5秒)
3. 应用重连新主库,查询所有记录的ID 返回1000条记录,无丢失
4. 用pt-table-checksum对比新旧主库数据 校验结果一致(DIFF=0)

场景2:高并发写入时切换

测试步骤 预期结果
1. 启动多线程压测工具(如sysbench),持续写入数据 主从复制延迟保持正常(Seconds_Behind_Master < 1s)
2. 强制杀死主库进程 从库自动提升为主库
3. 检查压测日志:记录最后一次成功写入的ID(如MAX(id) 新主库应包含该ID
4. 校验数据:SELECT COUNT(*) + pt-table-checksum 数据总量一致,无差异

场景3:事务中的切换(严苛场景)

测试步骤 预期结果
1. 主库执行大事务:
BEGIN;
INSERT 1000行;
UPDATE 1000行;
COMMIT;
事务未提交时切换,新主库不应出现部分数据
2. 在COMMIT前触发主库宕机 事务自动回滚,新主库中无该事务的脏数据
3. 检查binlog位置(SHOW MASTER STATUS 新主库的binlog position ≥ 旧主库事务开始位置

场景4:网络分区(脑裂场景)

测试步骤 预期结果
1. 模拟主库网络隔离(iptables阻断流量) 集群自动检测故障,触发从库切换
2. 旧主库恢复网络后尝试写入数据 写入失败(因旧主库已被降级为从库,且read_only=ON
3. 人工介入恢复旧主库:重新配置复制指向新主库 旧主库从新主库同步数据,最终数据一致

三、关键工具与技术选型

  1. 数据生成与压测
    • sysbench:模拟OLTP读写负载
    • 自定义脚本:插入带哈希值的数据(如MD5(CONCAT(id, data))
  2. 数据一致性校验
    • Percona Toolkitpt-table-checksum(低锁表风险)
    • MySQL内置校验CHECKSUM TABLE(适用于小表)
  3. 故障注入
    • Chaos Engineering工具
      • Chaos Mesh(K8s环境):模拟Pod故障、网络延迟
      • kill -9:强制终止MySQL进程
  4. 复制状态监控
    • SHOW SLAVE STATUS:检查Seconds_Behind_Master, Last_IO_Error
    • Prometheus + mysqld_exporter:实时监控复制延迟

四、自动化实现方案(Python示例)

import pymysql
import subprocess

def test_failover_consistency():
    # 1. 初始化数据
    master_conn = pymysql.connect(host="master", user="test")
    with master_conn.cursor() as cursor:
        cursor.execute("INSERT INTO test.data (id, hash) VALUES (1, MD5('data1'))")
        master_conn.commit()
    
    # 2. 触发故障切换(通过Chaos Mesh API或kubectl)
    subprocess.run("chaosd attack network delay --latency 500ms --duration 10m", shell=True)
    
    # 3. 等待切换完成(监控新主库选举)
    new_master = wait_for_new_master()  # 实现集群状态检测
    
    # 4. 验证数据
    new_conn = pymysql.connect(host=new_master, user="test")
    with new_conn.cursor() as cursor:
        cursor.execute("SELECT hash FROM test.data WHERE id=1")
        assert cursor.fetchone()[0] == "a1b2c3d4..."  # 预期哈希值
    
    # 5. 校验全局一致性
    subprocess.run("pt-table-checksum --host={new_master} --databases test", shell=True)
    # 解析pt-table-checksum输出,确认DIFF=0

def wait_for_new_master(timeout=30):
    # 实现逻辑:轮询集群状态API或查询MySQL元数据库(如MGR的`performance_schema.replication_group_members`)
    ...

五、注意事项

  1. GTID优先:确保开启GTID(gtid_mode=ON),避免binlog position切换后数据错位。
  2. 半同步复制:配置rpl_semi_sync_master_wait_point=AFTER_SYNC,确保事务提交前至少同步到一个从库。
  3. 脑裂防护:使用中间件(ProxySQL)或数据库代理(如MySQL Router)自动屏蔽旧主库写入。
  4. 数据验证时机:切换后等待1-2倍复制延迟时间再校验,避免误报。

面试回答点睛
强调设计中的破坏性测试思维(如主动注入事务中断、网络分区)和自动化闭环能力(从故障注入到结果校验全流程自动化)。可补充:“我会在K8s环境中用Chaos Mesh模拟生产级故障,并通过校验服务化接口将结果集成到自动化测试平台”。

posted @ 2025-08-01 14:47  程煕  阅读(21)  评论(0)    收藏  举报