嘿,你忘记写博客了~

盛年不重来,一日难再晨,及时宜自勉,岁月不待人....

binlog 底层写入机制及高并发写入事务性能优化

发布时间:2020-11-12编辑:windydeng浏览(176)评论览(0)

    接下来,我们依然基于 InnoDB 引擎来介绍 binlog 写入机制。

    InnoDB无论是对事务支持,还是对并发锁的支持,InnoDB 都是相对于 MyISAM 引擎更好的选择。

    和 redo log 一样,binlog 也只关心数据库更新操作(插入、删除、更新),查询操作不对对数据库有更改,所以记录下来也没有意义。

    为了性能考虑,binlog 也不会直接写入磁盘,MySQL 会为每个线程分配独立的 binlog cache(内存块,类似 redo log buffer),分配时机是在事务开启后第一次执行 DDL/DML 语句,然后将所有更新操作先记录到 binlog cache。

    这个 binlog cache 大小是有上限的,可以通过 binlog_cache_size 配置项调节,默认是 32 KB:

    如果超过这个限制,会将 binlog cache 中的缓存日志刷新到存储在磁盘里的 binlog 临时文件(redo log buffer 则是在超过容量一半时直接刷新到 redo log),同时清空 binlog cache,这个临时文件的大小则可以通过 max_binlog_cache_size 配置项配置:

    之后会清空对应的 binlog cache 和 binlog 临时文件,至此就完成了一个事务的 binlog 日志写入操作。

    需要注意的是每个事务线程都有自己的 binlog cache 和 binlog 临时文件,但是会共用同一个 binlog 文件。



    sync_binlog

    如果更细致的划分的话,真正持久化到磁盘 binlog 日志也是分两步进行的,首先会将日志持久化达到操作系统的文件系统页面缓存(FS Page Cache),然后再根据一定的策略真正写入 binlog 磁盘文件,这个策略可以通过 sync_binlog 配置项来设置:

    • sync_binlog=0:表示每次提交事务都写入到文件系统页面缓存,不持久化到 binlog 磁盘文件;

    • sync_binlog=1:表示每次提交事务都会立即写入 binlog 磁盘文件;

    • sync_binlog=N(N>1):表示每次提交事务都写入到文件系统页面缓存,累积到 N 个事务后才持久化到 binlog 磁盘文件。

    这样做的原因当然是为了性能考虑,写入到文件系统页面缓存相较于持久化到磁盘的系统开销更小,可以忽略不计,但是也有风险,就是服务器崩溃重启后文件系统页面缓存就不存在了,但是如果只是服务器中的 MySQL 进程崩溃重启,则页面缓存中的数据依然有效,所以在高并发场景下,上述 sync_binlog 可以设置为一个大于 N 的值,比如 100-1000,其风险是服务器崩溃重启后(概率很低),其中累积的 binlog 日志会丢失。

    InnoDB 后台进程每隔 1s 将 redo log buffer 日志刷新到 redo log 时底层就是借助了页面缓存作为中介,并不是直接持久化到 redo log 磁盘文件的。同理 innodb_flush_log_at_trx_commit 配置为 2 的时候,也存在服务器重启后累积的日志数据丢失的风险


    我们知道在数据库写入操作时真正涉及磁盘操作的也就是这里的两个日志写入了,更新的数据页是在内存 Buffer Pool 中完成的,所以降低了这两个日志的磁盘 IO 也就等同于优化了写入性能。

    因此,我们可以通过将上面介绍的 sync_binlog 配置为 N(N > 1),innodb_flush_log_at_trx_commit 配置为 2 调整日志真正写入磁盘文件的时机来优化高并发写入事务的性能

    这样一来,我们就可以实现 binlog 和 redo log 的组提交,尽可能减少磁盘 IO,这里存在的潜在风险是第 3 步之前服务器崩溃重启后页面缓存中累积的重做日志和 binlog 日志会丢失,不能恢复这期间的更新数据,但是 MySQL 异常崩溃重启后可以不受影响。实际情况下,除了机房断电等不可控因素,基本不会出现服务器异常崩溃重启的情况。

关键字词:binlog 底层写入机制及高并发写入事务性能优化