|
适合读者:DBA / 后端架构师 / 运维工程师关键词:MySQL 复制、binlog_do_db、replicate_do_db、数据不一致
在许多 MySQL 体系的数据库环境中,为了降低 binlog / relay log 日志量、缓解从库复制压力或减少同步延迟,往往会引入 主库 binlog 过滤 或 从库复制过滤 的配置方案。 这些手段在一定程度上能够缓解资源消耗,但如果对其工作机制理解不充分,使用了不合理的过滤策略,极易引入隐蔽且不可逆的数据不一致风险。更为危险的是,这类问题在系统运行过程中通常不会立刻暴露,当业务侧发现数据异常时,往往已经无法通过常规手段进行补救。
本文将从 主库与从库两种过滤方式的实现机制入手,分析它们各自的优缺点及潜在风险。
明确主库和从库在处理 SQL 和 row event 时的判断逻辑存在差异。
判断发生在 SQL 执行完成之后。
binlog_do_db / binlog_ignore_db 仅根据当前会话的 USE db 判断,而不关注 SQL 实际操作的目标表。
判断发生在 SQL Thread 回放阶段
判断依据包括:
**结论:**当主库和从库判断条件不一致时,即使 binlog 已记录,从库也可能未执行对应 row event,从而导致数据不一致。
主库参数设置:
binlog_do_db = db1
主库执行SQL:
USE db1;
INSERT INTO db2.t2 VALUES (1);
执行结果:
db2.t2,与 USE db1 不一致。从库复制过滤前提条件就是主库的 binlog 必须完整。
说明:
Replicate_Do_DB/Replicate_Ignore_DB 这两个参数一个是只同步某些库,另一个是只忽略某些库,判断依据是 relay log 中记录 use 的数据库,并不是 SQL 语句实际操作的库。
测试:
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 exist
结论:
从库报错表不存在,所以这样会导致从库同步数据失败,因为 use 的是 test 库。
风险:
多库写入(跨库 SQL)、存储过程、触发器、应用层不指定 USE 库都会导致数据不同步的风险。
说明:
Replicate_Do_Table/Replicate_Ignore_Table 这两个参数一个是只同步指定表,另一个是只忽略指定表,两个参数都不支持通配符,可以精确到表但使用要确保库名表名正确。
测试:
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)
结论:
由于主库执行 rename 操作将 t1 表更为 t1_bak,t1_tmp 更为 t1,而从库忽略了 t1_tmp 导致 sql 同步失败,如果业务往新 t1 表插入数据从库就会因表不存在而断开复制链路,这是典型的“表级过滤被 DDL 绕过”事故。
风险:
说明:
Replicate_Wild_Do_Table/Replicate_Wild_Ignore_Table 这两个参数一个是同步指定表,另一个是忽略指定表,两个参数都支持通配符,使用要确保库名表名没有通配符的隐患存在。
匹配方式:%、_(LIKE 语义)
测试:
忽略日志类表,不需要同步到从库。
STOP SLAVE;
CHANGE REPLICATION FILTER Replicate_Wild_Ignore_Table = (test1.log%);
START SLAVE;
一年后业务上线新业务 test1.log_important
主库查看数据:
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 | 匹配范围过宽,通配符需要转义 | 可用,前提是确保通配符不会影响其他表 |
合作电话:010-64087828
社区邮箱:greatsql@greatdb.com


