对Binlog的写入过程
在事务执行过程中,binlog首先写入binlog cache。提交事务后,binlog cache将写入binlog文件。一个交易的binlog是原子的,不管多大,都要保证完整性。
将为每个客户端线程分配一个大小由binlog_cache_size控制的binlog cache。当Binlog cache超过阈值时,它将临时保留在磁盘上。提交事务后,将binlog cache的整个事务保留在磁盘上,并清除binlog cache。
如上所示,每个客户端线程都有自己的binlog cache,但共享binlog文件。
上面的write是指将binlog cache写入文件系统的page cache,没有写入磁盘,因此速度很快。
Fsync是占用磁盘IOPS的实际磁盘写入操作。
Write和fsync的写入时间由sync_binlog控制。
Sync_binlog=0:每次提交事务时,只有write,fsync不是Sync_binlog=1:每次提交事务时,fsync;Sync_binlog=N(N1):每次提交事务时都是write,累计N个事务后运行fsync。发生I/o瓶颈时,建议将sync_binlog设置为较大的值。将n设置为100-1000更为常见。但是,如果主机异常重新启动,最近提交的n个事务binlog将有丢失的危险。
重做日志写入过程
前面介绍的redo log的写入操作首先写入redo log cache,详细状态如下:
Redo log对应于上述三种状态:1、MySQL应用程序中的redo log buffer。2、从write到文件系统的页面缓存,没有执行实际的写磁盘操作(fsync)。3、fsync运行后,写磁盘关闭。
InnoDB有一个后台线程,每秒调用write以将redo log buffer的日志写入文件系统的page cache,然后调用fsync以持续到磁盘。Redo log buffer是共享的,因此某些正在运行的事务的Redo log也可以持续到磁盘上。
通常,MySQL中的“双1”操作是指sync _ binlog=1和inno db _ flush _ log _ at _ Trx _ commit=1。如果将Innodb_flush_log_at_trx_commit设置为1,则redo log必须在prepare阶段持续一次,因此[双1]配置为每次提交事务时两次,一次为binlog。
为了控制Redo log的写入策略,innodb_flush_log_at_trx_commit为1,0:每次提交事务时,仅向redo log buffer写入。2、1:每次提交事务时,在磁盘上持续。3、2:每次提交事务时,都会将其写入文件系统的page cache中。
重做日志实际上触发了fsync操作写入磁盘。1、后台每秒执行线程轮询一次。2、如果innodb_flush_log_at_trx_commit设置为1,则在提交事务处理时触发。3、innodb_log_buffer_size是设置重做日志大小的参数,当重做日志缓冲达到innodb_log_buffer_size/2时触发
提交组
MySQL有一个组提交机制,可优化磁盘持续性的开销。首先介绍日志逻辑序列号(log sequ)
ence number,LSN),它是用来对应每个 redo log 写入点的递增序列号。每次写入长度为 length 的 redo log,LSN 就会加上 length。下面是 3 个并发事务(trx1、trx2、trx3)在 prepare 阶段都写完了 redo log buffer,然后组提交持久化的过程。其中 3 个事务对应的 LSN 分别是:50、120、160。
- trx1 是最先到达的,会被选为组 leader;
- 当 trx1 准备提交的时候,组里面已经有 3 个事务了,此时 LSN 变成了 160;
- trx1 写盘结束后,LSN 小于 160 的区块都已经被持久化;
- 此时 trx2 和 trx3 就可以直接返回了。
组提交优化
从上面描述可以看出,一次组提交里面的组员越多,节约磁盘 IOPS 的效果越好。在并发场景下,一个事务写完 redo log 之后,fsnyc 越晚调用,组员可能越多,其节约IOPS 的效果越好。binlog 和 redo log 的执行过程简图如下所示:
上面 binlog 的写入是 1 个步骤,事实上 binlog 的写入也是分成 2 步的:1、先将 binlog 从 binlog cache 写入磁盘的 page cache;2、然后再调用 fsync 持久化。为了让组提交的效果更好,把 redo log 做 fsync 的时间调整到了 binlog write 之后,如下所示:
从上图的流程可以看出,binlog 的写盘也可以组提交了。当上面执行 binlog: fsync 时,可以将需要写盘的 binlog 一起写入(事务完整 binlog),这样也可以减少一部分 IOPS 的开销。
通常情况下 redo log prepare: fsync 阶段执行的时间较短,此时可能binlog 的组提交可能没有 redo log 的组提交效果那么好。此时可以通过下面 2 个参数来提升 binlog 组提交的效率:
- binlog_group_commit_sync_delay:表示延迟多少微秒后,再执行 fsync;
- binlog_group_commit_sync_no_delay_count:表示累计多少次后,在调用 fsync;
上面 2 个参数是 或 的关系,满足其中一个就可以触发 fsync。
WAL 机制可以减少磁盘的写入次数,主要得益于下面 2 个方面:
1、redo log 和 binlog 都是顺序写,比磁盘的随机写要快;2、组提交机制可以大幅度减少磁盘的IOPS 消耗。
总结
当MySQL 出现了 IO 上面的性能问题,可以考虑下面的优化策略。
- 设置 binlog_group_commit_sync_delay 和 binlog_group_commit_sync_no_delay_count。可以使用故意等待来减少,binlog 的写盘次数,没有数据丢失的风险,但是会有客户端响应变慢的风险。
- 设置 sync_binlog 设置为 100~1000 之间的某个值。这样做存在的风险是可能造成 binlog 丢失。
- 设置 innodb_flush_log_at_trx_commit = 2,可能会丢数据。
参考:《极客时间:MySQL实战》、《高性能MySQL》
1.《【长虹bin数据怎么写入】MySQL中的binlog和redo log写原则》援引自互联网,旨在传递更多网络信息知识,仅代表作者本人观点,与本网站无关,侵删请联系页脚下方联系方式。
2.《【长虹bin数据怎么写入】MySQL中的binlog和redo log写原则》仅供读者参考,本网站未对该内容进行证实,对其原创性、真实性、完整性、及时性不作任何保证。
3.文章转载时请保留本站内容来源地址,https://www.lu-xu.com/why/3027581.html