MySQL binlog和redolog的写入机制
binlog的写入机制
每个线程都会先将日志写入到binglog cache, 事务提交的时候,再把binlog cache写到binlog文件中。所有线程都写一个binlog日志。
binlog_cache_size
用于控制单个线程内binlog cache 所占内存的大小,如果超过了这个参数规定的大小,就要暂存到磁盘。
write 和 fsync 的时机,是由参数 sync_binlog 控制的:
- sync_binlog=0 的时候,表示每次提交事务都只 write,不 fsync;
- sync_binlog=1 的时候,表示每次提交事务都会执行 fsync;
- sync_binlog=N(N>1) 的时候,表示每次提交事务都 write,但累积 N 个事务后才 fsync。
因此,在出现 IO 瓶颈的场景里,将 sync_binlog 设置成一个比较大的值,可以提升性能。在实际的业务场景中,考虑到丢失日志量的可控性,一般不建议将这个参数设成 0,比较常见的是将其设置为 100~1000 中的某个数值。
redo log 的写入机制
redo log 也是写入缓存,redo log buffer 之中。
redo log 事务提交时是否fsync,由参数innodb_flush_log_at_trx_commit
控制:
- 为0的时候,不做任何操作。redo log还是在redo log buffer之中。
- 为1的时候,每次提交事务就把redo log buffer fsync到磁盘
- 为2的时候,只是把redo log 写到page cache
此外,innodb 后台线程会每隔1秒将 redo log buffer中的日志,写入文件系统的page cache,然后调用fsync持久化到磁盘。因此,一个还没提交的事务,其在redo log buffer中的redo log会被后台线程持久化。
还有两种情况,redo log buffer会持久化
- redo log buffer大小占用达到innodb_log_buffer_size 一半,后台线程主动写盘。事务没有提交,只是写道page cache
- 当设置innodb_flush_log_at_trx_commit, 其他事务提交了,顺带将redo log buffer中的提交了
组提交机制
redo log 是有序号的,(log sequence number, LSN), 组提交机制指的时, 序号大的事务提交后,可以保证小于等于这个需要的redo log 都持久化到磁盘了。
(trx1, trx2, trx3) 这一组事务,trx3 提交了,调用fsync可以将之前的都持久化到磁盘。
binlog 也可以通过参数设置组提交的效果
如果你想提升 binlog 组提交的效果,可以通过设置 binlog_group_commit_sync_delay 和 binlog_group_commit_sync_no_delay_count 来实现。
- binlog_group_commit_sync_delay 参数,表示延迟多少微秒后才调用 fsync;
- binlog_group_commit_sync_no_delay_count 参数,表示累积多少次以后才调用 fsync。
如果你的 MySQL 现在出现了性能瓶颈,而且瓶颈在 IO 上,可以通过哪些方法来提升性能呢?针对这个问题,可以考虑以下三种方法:
- 设置 binlog_group_commit_sync_delay 和 binlog_group_commit_sync_no_delay_count 参数,减少 binlog 的写盘次数。这个方法是基于“额外的故意等待”来实现的,因此可能会增加语句的响应时间,但没有丢失数据的风险。
- 将 sync_binlog 设置为大于 1 的值(比较常见是 100~1000)。这样做的风险是,主机掉电时会丢 binlog 日志。
- 将 innodb_flush_log_at_trx_commit 设置为 2。这样做的风险是,主机掉电的时候会丢数据