聊聊复制过滤的那些隐藏陷阱
适合读者:DBA / 后端架构师 / 运维工程师 关键词:MySQL 复制、binlog_do_db、replicate_do_db、数据不一致 在许多 MySQL 体系的数据库环境中,为了降低 binlog / relay log 日志量、缓解从库复制压力或减少同步延迟,往往会引入 主库 binlog 过滤 或 从库复制过滤 的配置方案。 这些手段在一定程度上能够缓解资源消耗,但如果对其工作机制理解不充分,使用了不合理的过滤策略,极易引入隐蔽且不可逆的数据不一致风险。更为危险的是,这类问题在系统运行过程中通常不会立刻暴露,当业务侧发现数据异常时,往往已经无法通过常规手段进行补救。 本文将从 主库与从库两种过滤方式的实现机制入手,分析它们各自的优缺点及潜在风险。 明确主库和从库在处理 SQL 和 row event 时的判断逻辑存在差异。 判断发生在 SQL 执行完成之后。 判断发生在 SQL Thread 回放阶段 判断依据包括: 结论:当主库和从库判断条件不一致时,即使 binlog 已记录,从库也可能未执行对应 row event,从而导致数据不一致。 执行结果: 从库复制过滤前提条件就是主库的binlog必须完整。 说明: Replicate_Do_DB/Replicate_Ignore_DB 这两个参数一个是只同步某些库,另一个是只忽略某些库,判断依据是relay log中记录use的数据库,并不是SQL语句实际操作的库。 测试: 主库查看数据: 从库查看数据: 结论: 从库报错表不存在,所以这样会导致从库同步数据失败,因为use的是test库。 风险: 多库写入(跨库SQL)、存储过程、触发器、应用层不指定USE库都会导致数据不同步的风险。 说明: Replicate_Do_Table/Replicate_Ignore_Table 这两个参数一个是只同步指定表,另一个是只忽略指定表,两个参数都不支持通配符,可以精确到表但使用要确保库名表名正确。 测试: 主库查看数据: 从库查看数据: 结论: 由于主库执行rename操作将t1表更为t1_bak,t1_tmp更为t1,而从库忽略了t1_tmp导致sql同步失败,如果业务往新t1表插入数据从库就会因表不存在而断开复制链路,这是典型的“表级过滤被 DDL 绕过”事故。 风险: 说明: Replicate_Wild_Do_Table/Replicate_Wild_Ignore_Table 这两个参数一个是同步指定表,另一个是忽略指定表,两个参数都支持通配符,使用要确保库名表名没有通配符的隐患存在。 匹配方式: 测试: 忽略日志类表,不需要同步到从库。 一年后业务上线新业务test1.log_important 主库查看数据: 从库查看数据: 结论: 风险:聊聊复制过滤的那些隐藏陷阱
一、背景
二、复制过滤的判断逻辑
2.1 主库:是否写 binlog
binlog_do_db / binlog_ignore_db 仅根据当前会话的 USE db 判断,而不关注 SQL 实际操作的目标表。2.2 从库:是否执行 relay log
三、主库过滤参数及风险
3.1 binlog_do_db / binlog_ignore_db 的行为示例
主库参数设置:
binlog_do_db = db1
主库执行SQL:
USE db1;
INSERT INTO db2.t2 VALUES (1);db2.t2,与 USE db1 不一致。3.2 相关风险
四、从库复制过滤参数及风险
4.1 常用复制过滤参数
4.2 复制或忽略库参数
STOP SLAVE;
CHANGE REPLICATION FILTER Replicate_Do_DB = test1;
START SLAVE;USE test;
CREATE TABLE TEST1.T1 LIKE TEST.T1;
INSERT INTO TEST1.T1 VALUES(1,'A');greatsql> SELECT * FROM TEST1.T1;
+----+-------+
| id | cname |
+----+-------+
| 1 | A |
+----+-------+
1 row in set (0.00 sec)greatsql> SELECT * FROM TEST1.T1;
ERROR 1146 (42S02): Table 'test1.t1' doesn't exist4.3 复制或忽略表参数
STOP SLAVE;
CHANGE REPLICATION FILTER Replicate_Ignore_Table= (test1.t1_tmp);
START SLAVE;RENAME TABLE test1.t1 TO test1.t1_bak;
RENAME TABLE test1.t1_tmp TO test1.t1;greatsql> use test1
Database changed
greatsql> show tables;
+-----------------+
| Tables_in_test1 |
+-----------------+
| t1 |
| t1_bak |
+-----------------+
2 rows in set (0.01 sec)greatsql> USE test1
Database changed
greatsql> SHOW tables;
+-----------------+
| Tables_in_test1 |
+-----------------+
| t1_bak |
| t1_tmp |
+-----------------+
2 rows in set (0.01 sec)4.4 指定复制或忽略库参数
%、_(LIKE 语义)STOP SLAVE;
CHANGE REPLICATION FILTER Replicate_Wild_Ignore_Table = (test1.log%);
START SLAVE;greatsql> USE test1
Database changed
greatsql> SHOW tables;
+-----------------+
| Tables_in_test1 |
+-----------------+
| log_important |
+-----------------+
1 row in set (0.00 sec)greatsql> USE test1
Database changed
greatsql> SHOW tables;
Empty set (0.00 sec)log_important 被 log_% 命中新业务数据未同步到从库,主从复制正常但是从库数据丢失,如果主库故障切换到从库才发现数据不一致就会导致故障,这是典型的“通配规则忽略业务表”事故。五、最常见的踩坑配置
主库 从库 风险 是否推荐 binlog_do_db Replicate_Do_DB/Replicate_Ignore_DB 跨库静默丢数据 不推荐 binlog_do_db replicate_wild_ignore 从库失效 不推荐 binlog_ignore_db 无过滤 永久不可补 不推荐 无过滤 Replicate_Do_DB/Replicate_Ignore_DB 跨库静默丢数据 不推荐 无过滤 Replicate_Do_Table/Replicate_Ignore_Table 与DDL操作存在冲突,人工维护成本高 可用,前提是过滤表数量少 无过滤 Replicate_Wild_Do_Table/Replicate_Wild_Ignore_Table 匹配范围过宽,通配符需要转义 可用,前提是确保通配符不会影响其他表 六、最终建议(可直接当规范)