MySQL主从切换自动化用例设计
设计MySQL主从切换的自动化测试用例,核心是将“切换触发、业务模拟、状态监控、数据校验”全流程自动化,覆盖正常、异常、边界场景,同时确保测试可重复、结果可量化。以下是基于“场景驱动+工具链集成”的自动化测试方案设计。
一、自动化测试框架与工具链选型
自动化测试需解决“环境快速重建、操作自动化、校验标准化”三大问题,推荐工具链如下:
环节 | 工具/技术 | 作用 |
---|---|---|
测试框架 | Python + pytest | 管理测试用例、断言结果、生成报告 |
数据库操作 | pymysql / SQLAlchemy | 自动执行SQL(如查询主从状态、写入测试数据) |
主从环境部署 | Docker + docker-compose | 快速拉起主从架构(1主2从),支持环境重置(每次测试前初始化) |
切换触发工具 | 自定义Shell脚本 + MHA | 手动切换(执行SQL命令)或自动切换(调用MHA的masterha_manager) |
数据一致性校验 | 自定义校验脚本 + pt-table-checksum | 自动计算表checksum、对比行数、校验特殊对象(视图/存储过程) |
业务模拟 | 多线程写入脚本 | 模拟并发业务写入(INSERT/UPDATE/DELETE),生成可追溯的测试数据 |
监控与日志 | 日志模块(logging) + Prometheus | 记录切换耗时、同步延迟等指标,收集异常日志 |
二、核心测试场景与自动化用例设计
按“基础功能→复杂场景→异常容错”的层级覆盖,每个用例包含“前置条件→执行步骤→预期结果”三要素,通过代码实现全流程自动化。
场景1:正常切换(无业务写入时)
测试目标:验证无增量数据时,切换后新主库与原主库数据完全一致,业务可正常读写。
自动化步骤 | 技术实现细节 |
---|---|
1. 环境初始化:用Docker启动1主2从架构,初始化测试数据(含5张表,覆盖int/varchar/blob等类型,含主键/外键) | 编写docker-compose.yml 定义主从配置(如server-id、binlog开启),启动后执行init_data.sql 自动生成测试数据 |
2. 检查主从同步状态:确认所有从库Seconds_Behind_Master=0 ,Slave_IO/SQL_Running=Yes |
用pymysql连接从库,执行show slave status\G ,解析结果并断言同步正常 |
3. 暂停业务写入:通过API关闭模拟写入脚本(确保切换期间无新数据) | 调用写入脚本的停止接口(如HTTP请求),或设置全局变量is_writing=False |
4. 自动触发切换:选择从库1作为新主库,执行切换命令(stop slave; reset slave all; ) |
编写Python函数trigger_switch(new_master_ip) ,通过SSH执行切换SQL命令 |
5. 切换业务连接:修改测试客户端的数据库连接地址为新主库IP | 调用配置中心API(如Nacos)更新连接参数,或直接修改测试脚本的db_config |
6. 校验数据一致性: ① 对比新主库与原主库所有表的行数 ② 计算表的MD5校验和(忽略自增ID顺序) ③ 校验视图、存储过程定义是否一致 |
① 执行select count(*) from 表名 对比行数② 用 checksum table 表名 计算校验和③ 查询 information_schema.VIEWS 对比视图定义 |
7. 校验业务可用性:在新主库执行100条随机读写操作(INSERT/SELECT),确认无报错 | 生成随机SQL(如INSERT INTO test (col) VALUES (随机值) ),执行后断言无异常 |
场景2:有增量写入时的切换
测试目标:验证切换过程中持续写入的增量数据,在新主库中完整可见,无丢失/重复。
自动化步骤 | 技术实现细节 |
---|---|
1. 环境初始化:同场景1,额外启动“并发写入脚本”(10个线程,每秒共写入100条数据,每条数据含create_time=当前时间戳 ) |
用Python的threading 模块实现并发写入,每条数据记录唯一标识(如uuid() )以便追溯 |
2. 记录切换前的基准点: ① 原主库的binlog位置( show master status )② 写入脚本的“切换前最后一条数据ID” |
用变量pre_switch_binlog_pos 记录binlog位置,pre_switch_last_id 记录最后写入的uuid |
3. 触发切换:在写入脚本运行中,执行场景1的切换步骤4-5(不暂停写入) | 切换过程中,写入脚本持续生成数据(记录switch_start_time 和switch_end_time ) |
4. 校验增量数据完整性: ① 统计切换期间( switch_start_time 至switch_end_time )写入的总条数② 在新主库中查询该时间段的记录数,确认相等 ③ 随机抽取10%的记录,对比内容是否一致 |
① 从写入脚本的日志中统计增量总条数(total_increment )② 新主库执行 select count(*) from test where create_time between ... ③ 用 select * from test where uuid in (随机抽取的ID列表) 对比内容 |
5. 校验大事务一致性:切换前启动一个未提交的大事务(插入1万行数据),切换过程中提交,验证新主库是否完整同步 | 用begin; INSERT ... 开启事务,切换开始后执行commit; ,新主库查询该表行数是否+1万 |
场景3:异常场景切换(主库宕机)
测试目标:验证主库突然宕机时,自动切换工具(如MHA)能正确触发切换,且数据丢失量在可接受范围(如≤1秒)。
自动化步骤 | 技术实现细节 |
---|---|
1. 环境初始化:部署主从架构+MHA(Manager+Node),配置自动切换参数(如检测间隔3秒,失败阈值2次) | 用Docker部署MHA,修改masterha_default.cnf 配置故障检测参数 |
2. 启动持续写入:同场景2,记录每条数据的写入时间戳 | 写入数据含write_timestamp=UNIX_TIMESTAMP() |
3. 模拟主库宕机:执行docker stop 主库容器 或kill -9 主库进程ID |
用Python的subprocess 模块执行系统命令,强制终止主库 |
4. 监控MHA自动切换:通过MHA的日志(/var/log/masterha/ )确认切换触发,记录切换耗时(switch_duration = 切换完成时间 - 主库宕机时间 ) |
用tail -f 监控MHA日志,匹配“Master switched to ...”关键字,计算耗时 |
5. 校验数据丢失量: ① 找到主库宕机前最后一条成功写入的记录( max(write_timestamp) )② 新主库中找到最早未同步的记录( min(write_timestamp) )③ 计算时间差( data_loss = 未同步记录时间 - 最后同步记录时间 ) |
原主库重启后(可选)查询最后写入记录,新主库查询同步的最大时间戳,计算差值 |
6. 校验新主从架构:确认其他从库(含旧主库修复后)已指向新主库,同步正常 | 登录其他从库执行show slave status\G ,断言Master_Host 为新主库IP,同步状态正常 |
三、自动化校验核心方法(代码示例)
1. 主从同步状态校验
import pymysql
from pymysql.cursors import DictCursor
def check_slave_status(slave_ip, port=3306, user="root", password="123456"):
"""检查从库同步状态,返回是否正常"""
conn = pymysql.connect(host=slave_ip, port=port, user=user, password=password, cursorclass=DictCursor)
with conn.cursor() as cursor:
cursor.execute("show slave status")
slave_status = cursor.fetchone()
if not slave_status:
return False, "未配置从库"
# 校验IO线程和SQL线程是否运行,延迟是否为0
io_running = slave_status["Slave_IO_Running"] == "Yes"
sql_running = slave_status["Slave_SQL_Running"] == "Yes"
delay = slave_status["Seconds_Behind_Master"] == 0
conn.close()
return (io_running and sql_running and delay), f"IO: {io_running}, SQL: {sql_running}, Delay: {delay}"
2. 数据一致性校验(表checksum对比)
def calculate_table_checksum(db_ip, table_name):
"""计算表的checksum"""
conn = pymysql.connect(host=db_ip, user="root", password="123456")
with conn.cursor() as cursor:
cursor.execute(f"checksum table {table_name}")
checksum = cursor.fetchone()[1] # checksum结果在第二列
conn.close()
return checksum
def verify_data_consistency(old_master_ip, new_master_ip, tables):
"""对比新旧主库的表checksum"""
for table in tables:
old_checksum = calculate_table_checksum(old_master_ip, table)
new_checksum = calculate_table_checksum(new_master_ip, table)
assert old_checksum == new_checksum, f"表{table}数据不一致:旧主{old_checksum} vs 新主{new_checksum}"
3. 模拟并发写入
import threading
import time
import uuid
def concurrent_writer(db_ip, table_name, duration=60):
"""持续写入数据,duration秒后停止"""
conn = pymysql.connect(host=db_ip, user="root", password="123456", db="test")
start_time = time.time()
while time.time() - start_time < duration:
try:
data_id = str(uuid.uuid4())
create_time = time.strftime('%Y-%m-%d %H:%M:%S')
with conn.cursor() as cursor:
cursor.execute(f"INSERT INTO {table_name} (data_id, create_time) VALUES (%s, %s)", (data_id, create_time))
conn.commit()
print(f"写入成功:{data_id}")
time.sleep(0.01) # 控制写入频率
except Exception as e:
print(f"写入失败:{e}")
conn.rollback()
conn.close()
# 启动10个写入线程,持续30秒
for _ in range(10):
t = threading.Thread(target=concurrent_writer, args=("原主库IP", "test_table", 30))
t.start()
四、测试结果与报告自动化
- 核心指标收集:切换耗时(从触发到业务恢复)、数据丢失量(异常场景)、数据一致性结果(通过/失败)、业务中断时间。
- 报告生成:用pytest-html生成HTML报告,包含每个场景的步骤、截图(如主从状态截图)、日志片段。
- 告警机制:测试失败时(如数据不一致),通过邮件或企业微信通知测试人员,附带详细日志。
五、环境清理与复用
自动化测试后需快速重置环境,确保下次测试无干扰:
- 停止所有容器,删除数据卷(
docker-compose down -v
); - 重新启动容器,执行初始化脚本(自动创建主从、导入测试数据);
- 记录环境重置耗时(目标≤5分钟),确保测试效率。
总结
MySQL主从切换的自动化测试需围绕“场景全覆盖+执行无人工干预+校验可量化”设计,核心是通过代码将“环境准备-切换触发-数据校验”串联,结合Docker实现环境一致性,用多线程模拟真实业务压力,最终通过自动化工具链输出可靠的切换质量指标(如数据零丢失、切换耗时<30秒)。这种方案既能提升测试效率(支持每日定时执行),又能避免人工操作的疏漏,更贴近生产环境的真实场景。