《MySQL——redolog与binlog写⼊机制》
⽬录
WAL机制告诉我们:只要redo log与binlog保证持久化到磁盘⾥,就能确保MySQL异常重启后,数据可以恢复。
下⾯主要记录⼀下MySQL写⼊binlog和redo log的流程。
binlog写⼊机制
1、事务执⾏过程中,先把⽇志写到binlog cache,事务提交的时候,再把binlog cache写到binlog⽂件中。
2、binlog cache,系统为每个线程分配了⼀⽚binlog cache内存,参数binlog_cache_size控制单个线程内binlog cache⼤⼩。如果超过了这个⼤⼩就要暂存磁盘
3、事务提交的时候,执⾏器把binlog cache⾥完整的事务写⼊binlog中。并清空binlog cache
4、每个线程都有⾃⼰的binlog cache,共⽤⼀份binlog⽂件
5、write,是把⽇志写⼊到⽂件系统的page cache,内存中,没有持久化到磁盘,所以速度⽐较快,图中的fsync是将数据持久化到磁盘,占⽤磁盘的IOPS
关于何时write、fsync是由参数sync_binlog控制的:
1、sync_binlog = 0时,每次提交事务都只write,不fsync;
2、sync_binlog = 1时,每次提交事务都会执⾏fsync;
3、sync_binlog = N(N>1)时,表⽰每次提交事务都write,但累积N个事务后才fsync。
sync_binlog控制binlog真正刷盘的频率,对于⼀个IO⾮常⼤的情景,这个数字调⼤可以提⾼性能,但是如果容错率⾮常低的情况下,必须设为1.(sync_binlog设置为N对应的风险是:如果主机发⽣异常重启,会丢失最近N个事务的binlog⽇志)
redo log写⼊机制
事务在执⾏过程中,⽣成的redo log是要先写到redo log buffer的。
redo log buffer⾥⾯的内容并不需要每次⽣成后都要持久化到磁盘中。
如果事务执⾏期间MySQL发⽣异常重启,那么这部分⽇志就丢了。由于事务并没有提交,所以这时⽇志丢了也不会有损失。
事务没提交的时候,redo log buffer部分⽇志也是有可能被持久化到磁盘中的。
上⾯三个颜⾊表征了redo log可能的三种状态:
1、存在redo log buffer中,物理上是在MySQL进程内存中,即红⾊部分;
2、写到磁盘(write),但是没有持久化(fsync),物理上实在⽂件系统的page cache⾥⾯,即黄⾊部分;
3、持久化到磁盘,对应的是hard disk,也就是图中的绿⾊部分;
mysql下载哪个盘前两步是写内存,最后⼀步是磁盘IO,所以要在page cache够⼤且不影响写⼊page cache前将redo log 持久化到磁盘 。
为了控制redo log 的写⼊策略,InnoDB提供了innodb_flush_log_at_trx_commit参数,他有三种可能取值:
1、设置为0,每次事务提交的时候都只是把redo log留在redo log buffer中;
2、设置为1,每次事务提交的时候都只是把redo log直接持久化到磁盘;
3、设置为2,每次事务提交时都只是把redo log写到page cache;
与binlog不同,binlog是每个线程都有⼀个binlog cache,⽽redo log是多个线程共⽤⼀个redo log buffer。
InnoDB有⼀个后台线程,每隔1s,就会把redo log buffer中的⽇志,调⽤write写到⽂件系统的page cache,然后调⽤fsync持久化到磁盘,事务执⾏过程中的redo log也是直接写在redo log buffer上的,所以,未提交的事务的redolog也可能被持久化到磁盘。
还有两种场景也会导致没有提交的事务的redo log写⼊到磁盘中:
情形1:
redo log buffer占⽤的空间即将达到innodb_log_buffer_size⼀半的时候,后台线程会主动写盘。
(这⾥只是write,没有fsync)
情形2:
并⾏的事务提交的时候,顺带将这个事务的redo log buffer持久化到磁盘。
(事务A执⾏⼀半,部分redo log到buffer中;事务B提交,且 innodb_flush_log_at_trx_commit ,会把redo log buffer⾥的log全部持久化到磁盘中)
补充说明
两阶段提交在时序上redo log先prepare 再写binlog,最后再把redo log commit;
innodb_flush_log_at_trx_commit 设置成 1,prepare阶段redo log就已经落盘。所以redo log再commit的时候就不需要fsync了,只会write到⽂件系统的page cache中就够了。
sync_binlog 和 innodb_flush_log_at_trx_commit都设置为1,即⼀个事务完整提交前,需要等待两次
刷盘,⼀次是redo log(prepare阶段),⼀次是binlog。
组提交机制实现⼤量的TPS
⾸先介绍⽇志逻辑序列号(log sequence number,LSN)的概念。LSN是单调递增的,每次写⼊长度length的redo log,LSN的值就会加上length。
三个并发事务(trx1,trx2,trx3)在prepare阶段,都写完redo buffer,并持久化到磁盘。
对应的LSN为50、120、160.
对应流程:
1、trx1第⼀个到达,被选为这组的leader;
2、等trx1要开始写盘的时候,这个组⾥⾯已经有三个事务,这时候LSN也变成了160;
3、trx1去写盘的时候,LSN=160;trx1返回时,所有LSN<= 160的redo log都被持久化到磁盘中;
4、trx2与trx3直接返回。
总结:
⼀次组提交中,组员越多,节约磁盘IOPS的效果越好。如果是单线程,就只能⼀个事务对应⼀次持久化操作
两阶段提交
两阶
段提交细化
这样保证binlog也可以组提交了。由于step3速度快,所以集合到⼀起的binlog⽐较少,所以binlog的组提交效果不如redo log组提交。
提升binlog效果:
--1.binlog_group_commit_sync_delay :b表⽰延迟多少微秒后才调⽤fsync;
--2.binlog_group_commit_sync_no_delay_count :表⽰累积多少次以后才调⽤fsync;
理解WAL机制
WAL机制是减少磁盘写,可是每次提交事务都要写redo log和binlog ,磁盘读写次数没有变少。
所以WAL机制主要得益于两个⽅⾯:
--1、redo log和binlog都是顺序写,磁盘的顺序写⽐随机写速度要快
--2、组提交机制,可以降低磁盘IOPS消耗
如何提升IO性能瓶颈
1、设置binlog_group_commit_sync_delay和binlog_group_commit_sync_no_delay_count参数,减少binlog的写盘次数。这个⽅法是基于“额外故意等待”来实现的,可能会增加语句的响应时间,但是不会丢失数据
2、将sync_binlog设置为⼤于1的值(100~1000)。不过会有主机掉电时丢binlog⽇志的风险
3、将 innodb_flush_log_at_trx_commit 设置为2。会有主机掉电丢数据的风险
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论