面试官:我们的Mysql 从库比主库多数据了,分析下原因?
面试官:我们的Mysql 从库比主库多了几千条数据了,分析下原因?
我:是半同步复制吗?
面试官:就传统的异步复制
我:少数据说明主库redo没写到硬盘,没写到硬盘说明没有提交啊。但是怎么就把binlog同步到备库了呢?Mysql 的提交采用的是两阶段提交,要写应该都写的啊。
面试官:我提个醒吧,Mysql 的binlog 有哪些部分组成?
我:binlog cache 和本地 binlog file
面试官:对,就是binlog cache 导致的。
我有点蒙,没想明白……
思考
不妨你也想想什么原因呢?
.
.
.
.
.
.
事后想着想着就想到,会不会是他们采用的不是双1呢?很大可能就是这样。
innodb_flush_log_at_trx_commit
设置为1时,commit 完成必然写入了硬盘。如果为了提升性能改为了0或2,那么数据库或系统故障时是有可能丢失1s数据的。1s有多少数据很难估算,如果业务繁忙可能是上千,上万或更多。
双1 的另一个参数sync_binlog
对应的则是事务数,为了数据安全我们通常也设定为1,但是如果为了提升主库性能并且要保证从库复制的正常,我们可能会考虑改大该值,1000,2000 或更多,相应的从库也有丢失这么多数据的可能。
这样,如果参数innodb_flush_log_at_trx_commit
设置为0, sync_binlog 设置为2000. 系统崩溃前的最后1s内执行了7000条插入。那么可能遇到的情况就是主库丢失了7000条数据,而从库只丢失了1000条数据。虽然每条数据主库都自动提交了,但是主库却还没来得及把redo log buffer中的内容刷入到硬盘,系统就崩了,重启后内存数据自然全部丢失,而binlog cache中的数据则每2000条就刷一次到硬盘,所以只损失了最后1000条。
此间事了,那我们再思考下。
-
异步复制为什么存在丢失数据的风险?
-
半同步复制after_commit 后为什么又推出增强的半同步复制 after_sync?
-
半同步复制after_commit 在什么情况下会丢失数据?
-
半同步复制after_sync 能保证不丢失数据吗?
扩展
1.异步复制
主库发出commit命令,通知从库dump线程获取binlog日志,然后主库完成提交,不关心从库是否取了日志。
所以从库有没有获取到binlog,没人知道。
2.半同步复制-after_commit
主库发出commit,通知从库dump线程获取binlog日志,主库后台完成提交,但当前会话需等待从库接收完日志返回ACK(其他会话可以看到已变更的数据,但当前会话不能做任何操作,尚需等待ACK返回)。从库返回ACK则当前会话完成提交返回操作符。
可能的问题:从库还没写或没接收完binlog主从就异常了。但主库后台已经完成了提交。主库比从库多数据(主库已提交,从库缺失binlog)。
3.半同步复制-after_sync
主库发出commit,同时通知从库dump线程获取binlog日志,主库等待从库接收完日志返回ACK,从库返回则主库完成提交返回操作符,否则继续等待。
从库没写完,主库不会完成提交,所以主库不可能比从库多数据。但是极端情况下可能出现从库完成了binlog落盘,返回ACK给主库的时候主从异常了。导致的问题:从库比主库多数据(从库已接收binlog,但主库没得到ACK,所以没提交,事务进行了回滚。)这时可能导致的问题:1.从库比主库多数据;2.主库重新提交时,从库发生数据冲突。
3不能完全保证数据不丢失后,但3出现的概率要比2小得多
业务繁忙或遇到大事务的情况下,每秒可能产生几十、几百兆或更多的binlog,主从同步过程中,网络慢或从库写磁盘慢,都可能导致binlog在从库的落盘有延迟,这时候遇到数据库故障或系统故障,在2下很容易丢失binlog。
而在3下,无论从库写binlog多慢,主库都要等从库写完才能提交。从库写完后只需返回一个ACK确认消息,传输的内容就小的多了,出问题概率极小。除非网络IO撑满,ACK都接收不了。