本文章着重讲述2PC&GC,由此引申出binlog,redolog,innodb三者的纠缠,最后简单介绍一下并行复制的原理
2PC
action | binlog | -->redolog | -->innodb |
---|---|---|---|
prepare | noop | fsync | set TRX_PREPARED |
commit | write & fsync(sync_binlog) | fsync(innodb_flush_log_at_trx_commit) | set TRX_NOT_STARTED |
事务恢复机制:
1、TRX_COMMITTED_IN_MEMORY--->TRX_NOT_STARTED
2、TRX_NOT_STARTED 无需处理
3、binlog fsync & TRX_PREPARED ---> TRX_NOT_STARTED
4、TRX_ACTIVE---> rollback
prepare_commit_mutex:
在备份时刻,出现了binlog(T1 coo)与innodb(T3 commit)的不一致
主库:T1已经写入binlog但是没commited
从库: 备份恢复时,因为从库没有binlog,根据2PC,rollback T1,然后change master 到 innodb (T3 commit)的点,即使将T1 commit 的binlog拉取到从库,T1也已经丢失
解决方案:利用prepare_commit_mutex序列化事务提交,就能保证binlog和innodb的一致,只能通过sync_binlog=X来合并binlog的fsync操作,数据安全性降低,若sync_binlog=1, binlog写入性能将大大降低
comment:
1、2PC操作保证了binlog和redo log一致性(恢复机制)和持久性(fsync),
2、事务恢复时,以binlog的数据为标准,若事务binlog已经写入,则将事务前滚提交;
3、序列化事务,对服务吞吐量有很大的影响
GC
5.6 GC binlog G
stage | binlog | redolog | innodb |
---|---|---|---|
prepare | noop | fsync | set TRX_PREPARED |
Gflush | write | noop | noop |
Gsync | fsync(sync_binlog) | noop | noop |
Gcommit | noop | noop | set TRX_NOT_STARTED |
5.7 GC binlog & redolog
stage | binlog | redolog | innodb |
---|---|---|---|
prepare | noop | set LSN | set TRX_PREPARED |
Gflush | write | ::fsync | noop |
Gsync | fsync(sync_binlog) | noop | noop |
Gcommit | noop | noop | set TRX_NOT_STARTED |
::fsync是在Gflush之后,reloglog直接统一fsync到LSN
总结:
GC 则摒弃了prepare_commit_mutex,将事务提交步骤分成了prepare,
(flush,sync, commit)三段,三段可以线程并发操作(粗略认为提高了二倍效率)当然这三段是个整体2PC处理
however,由于没有了prepare_commit_mutex,那么备份时又可能再现binlog与innodb不一致的场景(在Gsync之后,Gcommit之前备份),那这又是如何规避的呢?详见xtrabackup
MySQL crash-safe replication
MySQL 数据丢失
主库crash safe 双一即可
从库crash safe
1、IO thread可以通过relay info重新拉取master 的binlog
2、SQL thread 的relay info一致性,现在是通过innodb表存储relay info,master info与relay info还有3个参数控制刷新:
sync_relay_log:默认为10000,即每10000次sync_relay_log事件会刷新到磁盘。为0则表示不刷新,交由OS的cache控制。
sync_master_info:若master-info-repository为FILE,当设置为0,则每次sync_master_info事件都会刷新到磁盘,默认为10000次刷新到磁盘;若master-info-repository为TABLE,当设置为0,则表不做任何更新,设置为1,则每次事件会更新表 #默认为10000
sync_relay_log_info:若relay_log_info_repository为FILE,当设置为0,交由OS刷新磁盘,默认为10000次刷新到磁盘;若relay_log_info_repository为TABLE,且为INNODB存储,则无论为任何值,则都每次evnet都会更新表。