欢迎光临散文网 会员登陆 & 注册

MySQL复制可能造成数据不一致的地方

2021-05-16 11:08 作者:Databend  | 我要投稿

上周在讲复制故障处理,利用DML在从主上手工造数据,导致主从复制中断,然后处理复制故障,同时给大家安利了:课程Demo程序:主从故障自动修复:zhishutech/ReplGurd (github.com)  建议fork|star | watch  有完善的地方请pull回来复制主从数据一致性校验、修复程序:pt-table-checksum/pt-table-sync 使用。


结课QA环节一个学生问到:老师除了误操作写了从节点造成数据不一致性外,还有哪些原因? 看到这个问题,当时我真的是一口鲜血喷在了屏幕上啊? 
在4月26日MySQL复制原理及应用中刚讲了复制原理及半同步中可能出现的数据不一致时间点,整整用了一节课,在5月10日课中,被问到这个问题。有点无语了。


怎么刚讲过,你们都忘了呢~~~ :) 好吧。当时就利用老师的特权给你们留个作业,回顾:MySQL复制原理及应用场景,试试能不能解答复制主从可能造成主从数据不一致的地方。果真有很给力的同学,不管什么是哪一届都还是有很多优秀的同学,第二天一早就收到一份作业,也分享出来,给各位一个参考:


主从复制可能造成不一致分析(作者A1364-路遥-北京)
异步复制本身对于数据一致性不做保证,不过使用得当也可以保证数据一致性,下面为了讨论方面,我们直接使用半同步的两个模式讨论。
MYSQL5.7 之前半同步复制采用的是 AFTER_COMMIT 方式--比 AFTER_SYNC 会有更大概率造成数据不一致


AFTER_COMMIT 是先做 REDO COMMIT 后传 BINLOG,做事务提交,只是不给客户端返回。


AFTER_COMMIT模式下丢失数据实验版本8.0.23 (版本不重要,原理没变,所有MySQL都一样,本期课程使用的MySQL 8.0.23)
主库参数

+-------------------------------------------+--------------+

| Variable_name | Value |

+-------------------------------------------+--------------+

| rpl_semi_sync_master_enabled | ON |

| rpl_semi_sync_master_timeout | 60000000000 |

| rpl_semi_sync_master_trace_level | 32 |

| rpl_semi_sync_master_wait_for_slave_count | 1 |

| rpl_semi_sync_master_wait_no_slave | ON |

| rpl_semi_sync_master_wait_point | AFTER_COMMIT |

| rpl_semi_sync_slave_enabled | OFF |

| rpl_semi_sync_slave_trace_level | 32 |

+-------------------------------------------+--------------+

从库参数

+-------------------------------------------+--------------+

| Variable_name | Value |

+-------------------------------------------+--------------+

| rpl_semi_sync_master_enabled | OFF |

| rpl_semi_sync_master_timeout | 60000000000 |

| rpl_semi_sync_master_trace_level | 32 |

| rpl_semi_sync_master_wait_for_slave_count | 1 |

| rpl_semi_sync_master_wait_no_slave | ON |

| rpl_semi_sync_master_wait_point | AFTER_COMMIT |

| rpl_semi_sync_slave_enabled | ON |

| rpl_semi_sync_slave_trace_level | 32 |

+-------------------------------------------+--------------+


从库上停掉IO_THREAD模拟从库异常stop replica io_thread;


主库上插入一条数据,此时会HANG住(但是这条数据已经写入了,开启一个会话是可以查到该数据的)
insert into t values(1);

开启新SESSION查询T表

select * from t;

+------+

| id |

+------+

| 1 |

+------+

开启另一个会话杀掉主库MYSQLD进程

pkill -9 mysqld

此时从库中是查不到这条数据的。
select * from t;

Empty set (0.00 sec)
如果此时发生主从切换则主从数据发生不一致。这也是after_commit模式复制中幻读现象。 如图:


AFTER_SYNC 是先传 binlog 后做 REDO COMMIT


极端有两种情况:1. 当主库还没来得及把日志传输到从库上;主库上在完成write binlog后crash2.日志已经传输到从库上,完成了wait slave ack,此时发生crash;应用端此时并没有接收到主库返回OK。情况1. 主库Crash恢复后,这个事务操作数据可以被commit,这种事务可以称为local commit或是幽灵事务,并没有真正的完成半同步。情况2. 产生脏数据,是一个业务没得到确认的事务。也可以称为幽灵事务。


在after_sync中,确实不会丢数据了,但有可能会多数据。 这种架构下复制故障:1062,1032类的错误,会发生在第一种情况,原始的master故障恢复后,做为新master的从。1062错误很容易出现,但1032错误可能被MySQL本身掩盖了。所以对于after_sync复制,最好的做法是原始主库故障后,可以对比一下最后一个GTID事务的内容或是直接自动化重建(云上的方案)


那么使用复制如何保证数据的绝对一致性呢?

1.复制一定是binlog row格式+gtid,同时在数据库故障时,注意local commit问题,引入数据校验机制。

 2. 复制环境绝对一致性属于伪命题,如果想要绝对的一致目前可以考虑MySQL Group Replication。 

3. 如果一定要用复制架构,同时又要绝对的一致性,考虑使用增强半同步after_sync结合session_track_gtids功能使用。

4. 复制推荐使用after_sync,同样要求半同步不允许退化成为异步。
5. 深入理解复制的原理,避免不适当的操作造成复制一致性: 大事务,较长DDL等操作。如果必须操作,可以考虑一些特殊的运维方式操作。

孔子曰:三人行,必有我师。大胆交流,不耻下问。加油,学到了才是真本事。欢迎交流指正。没有评论的公众号有点缺乏灵魂,灵魂需要你。
               

加入内部组织交流



MySQL复制可能造成数据不一致的地方的评论 (共 条)

分享到微博请遵守国家法律