一、写入机制
binlog的写入时机也非常简单,事务执行过程中,先把日志写到 binlog cache ,事务提交的时候,再把binlog cache写到binlog文件中。因为一个事务的binlog不能被拆开,无论这个事务多大,也要确保一次性写入,所以系统会给每个线程分配一个块内存作为binlog cache。
可以通过binlog_cache_size参数控制单个线程binlog cache大小,如果存储内容超过了这个参数,如果存储内容超过这个参数,会存储到磁盘中。
write和fsync的时机,可以由参数 sync_binlog 控制,默认是 0 。
1、sync_binlog为0时
为0的时候,表示每次提交事务都只write,由系统自行判断什么时候执行fsync。虽然性能得到提升,但是机器宕机,page cache里面的binglog 会丢失
2、sync_binlog为1时
表示每次提交事务都会执行fsync,就如同redo log 刷盘流程一样。
3、sync_binlog为n(n>1)时
表示每次提交事务都write,但累积N个事务后才fsync
在出现IO瓶颈的场景里,将sync_binlog设置成一个比较大的值,可以提升性能。同样的,如果机器宕机,会丢失最近N个事务的binlog日志
二、binlog与redolog对比
1、redo log
(1)它是物理日志 ,记录内容是“在某个数据页上做了什么修改”,属于InnoDB 存储引擎层产生的
(2)事务执行中写入
(3)让InnoDB存储引擎拥有了崩溃恢复能力
2、binlog
(1)是逻辑日志 ,记录内容是语句的原始逻辑,属于MySQL Server 层
(2)事务提交时写入
(3)保证mysql集群架构的数据一致性
三、两阶段提交
在执行更新语句过程,会记录redo log与binlog两块日志,以基本的事务为单位,redo log在事务执行过程中可以不断写入,而binlog只有在提交事务时才写入,所以redo log与binlog的 写入时机不一样
1、redo log与binlog两份日志之间的逻辑不一致,带来的问题
以update语句为例,假设id=2的记录,字段c为0,把字段c更新为1,sql为
update T set c=1 where id=2
假设执行过程中写完redo log日志后,binlog日志写期间发生的异常。
由于binlog没写完就异常,这时候binlog里面没有对应的修改记录。后面用binlog日志恢复数据,就会少这一次的更新,恢复出来的c为0,而master使用redo log日志恢复,此时c为1,最终数据不一致。
2、两阶段提交
为了解决两份日志之间的逻辑一致问题,InnoDB存储引擎使用两阶段提交方案。
(1)使用两阶段提交后,写入binlog时发生异常也不会有影响
(2)redo log设置commit阶段发生异常
并不会回滚事务,它会执行上图框住的逻辑,虽然redo log是处于prepare阶段,但是能通过事务id找到对应的binlog日志,所以MySQL认为是完整的,就会提交事务恢复数据