一、问题描述
版本5.6/5.7,最近遇到一个问题如下:
在从库端设置如下设置这两行
replicate-ignore-db=mysql
replicate-ignore-db=information
会出现问题1如下:
- 如果用户修改自己的密码,某些情况下不能进行主从同步
- 管理修改密码同样某些情况下不能进行主从同步
在从库端设置再加上一行,会出现问题2,如下:
replicate_wild_ignore_table=mysql.%
则修改密码的操作必定不能同步。对于设置了从库端的replicat ignore而言过程如下:
主库binlog(完整)->从库relay log(完整) ->apply event(应用过滤规则)
先匹配ignore-db然后匹配table进行过滤。详细过滤规则参考:
- Evaluation of Database-Level Replication and Binary Logging Options
二、分析问题1
首先如果设置了
replicate-ignore-db=mysql
replicate-ignore-db=information
那么对于DDL语句而言,由于没有map event存在,则会通过query event中的DB进行过滤,也就是说当前在哪个DB下面(use db)则会根据这个db进行过滤。
我们知道对于普通用户来讲一般能够看到information_schema和自己的db,如果用户使用:
use information_schema
alter user identified by ;
则这个操作将会在从库过滤掉。其次对于管理员账户而言能够看到的库更多包含mysql库,同样存在这个问题。
因此只要用户(包括管理员)通过use 操作进行了schema然后修改用户,那么则根据匹配规则有可能过滤掉。
三、分析问题2
如果设置如下:
replicate-ignore-db=mysql
replicate-ignore-db=information
replicate_wild_ignore_table=mysql.%
如果我们修改密前不进行use db,这个及时修改密码依旧会被过滤掉,因为不管是建立用户还是修改密码,最后都将转换为对mysql.user表的操作,这种情况下虽然ignore db不会被匹配到,但是ignore table却会匹配到。如下:
调用栈:
有兴趣的童鞋可以将断点打到rpl_filter.tables_ok上自行观察就可以了,实际上我们的整个replicate-ignore规则都体现在rpl_filter这样一个全局对象上如下,数据结构就是Rpl_filter:
Rpl_filter* rpl_filter;
有感兴趣的可以研究一下,对于过滤规则的代码我也没有深入研究过,但是应该难度偏小。