本文介绍 MySQL 的 binlog 和 redo log 写入机制和刷盘策略,以及如何提升 MySQL 的 IO 性能。
binlog 的写入机制
binlog 的写入流程是:
先将日志写入到 binlog cache 中,然后再 write page cache 到磁盘(文件系统向内核申请的一块内存空间,当 MySQL 进程重启时,不影响这块空间),最后 fsync 到磁盘。
每个事务对应的 binlog 是不能拆开的,所以必须一次性保存。每个线程有自己的 binlog cache,通过 binlog_cache_size 参数设置,但是多个线程共享同一个 binlog 文件。如果 binlog cache 存不下,就会存到磁盘中。
binlog 的刷盘策略,即 write 和 fsync 的时机,是由参数 sync_binlog
控制的:
一般不会将 sync_binlog 设置为 0,那样可能会丢失大量的日志。为了提高 IO 性能,可能会将 sync_binlog 设置为 100 ~ 1000 的值,这样只会丢失最近的 N 条日志。
redo log 的写入机制
redo log 的写入流程:
先将日志记录在 redo log buffer 中,然后再 write page cache,最后 fsync 到磁盘。并且,有一个后台线程,每隔一段时间就会将 redo log buffer 同步到磁盘。(可能事务未提交,但也同步到磁盘的情况)
redo log 的刷盘策略,由 InnoDB 提供了 innodb_flush_log_at_trx_commit
参数控制,它有三种可能取值:
注意,如果把 innodb_flush_log_at_trx_commit 设置为 1,那么 redo log 在两阶段提交的第一个 prepare 阶段就会刷盘,第二个 commit 阶段只会 write page cache。
双”1″配置
MySQL 的双”1″配置指的就是 innodb_flush_log_at_trx_commit=1 和 sync_binlog=1 。即一次事务提交,需要等待两次 fsync。
组提交(group commit)
这时候,你可能有一个疑问,这意味着我从MySQL看到的TPS是每秒两万的话,每秒就会写四万次磁盘。但是,我用工具测试出来,磁盘能力也就两万左右,怎么能实现两万的TPS?
解释这个问题,就要用到组提交 group commit
机制了。
这里,我需要先和你介绍日志逻辑序列号 LSN
(log sequence number)的概念。LSN是单调递增的,用来对应redo log的一个个写入点。每次写入长度为length的redo log, LSN的值就会加上length。
组提交举例:
对于多个并发事务,他们都写完了 redo log buffer,准备持久化到磁盘,那么会从这些事务中选择一个 leader,然后取他们中最大的 LSN,让这个 leader 带着最大的 LSN 取写盘,这样小于 LSN 的日志就都写到了磁盘,也就完成了一个组提交,其他事务直接返回即可。
所以,一次组提交中事务越多,可以节省的 IOPS 也就越多。
MySQL 在进行两阶段提交时,redo log 和 binlog 都是可以使用组提交的。此外,为了提高 binlog 使用组提交的效果,可以设置 binlog_group_commit_sync_delay
和 binlog_group_commit_sync_no_delay_count
来实现:
注意,如果 sync_binlog 设置为 0,那么 binlog_group_commit_sync_delay 会进行延迟,但不会 fsync。
MySQL的IO性能优化
在此基础上,可以通过以下方式对其进行优化:
[En]
Based on the above, it can be optimized in the following ways:
Original: https://www.cnblogs.com/flowers-bloom/p/mysql45-promote-io-performance.html
Author: flowers-bloom
Title: MySQL45讲之IO性能提升
原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/508082/
转载文章受原作者版权保护。转载请注明原作者出处!