「这是我参与2022首次更文挑战的第15天,活动详情查看:2022首次更文挑战」
前言
前面我们介绍了《Mysql InnoDB之Redo Log》其中提到了一些参数的配置,其实参数的配置就涉及到一些底层的流程,下面我们主要讲Redo Log的innodb_flush_log_at_trx_commit会涉及到Redo Log的写入流程。
Redo Log的写入流程
我们首先还是先看看官方文档对innodb_flush_log_at_trx_commit配置的描述。
innodb_flush_log_at_trx_commit
| 命令行格式 | --innodb-flush-log-at-trx-commit=# |
| 系统变量 | innodb_flush_log_at_trx_commit |
| 影响范围 | Global |
| 动态的 | Yes |
SET_VAR提示适用 | No |
| 类型 | Enumeration |
| 默认值 | 1 |
| 有效值 | 0,1,2 |
控制提交操作的严格ACID合规性与重新安排提交相关的 I/O 操作并分批完成时可能实现的更高性能之间的平衡。您可以通过更改默认值来获得更好的性能,但是您可能会在崩溃中丢失事务。
- 完全符合 ACID 要求默认设置 1。日志在每次事务提交时写入并刷新到磁盘。
- 设置为 0 时,日志每秒写入一次并刷新到磁盘。(停留在redo log buffer里,每秒刷新写入文件系统的page cache中,然后调用fsync持久化到磁盘)未刷新日志的事务可能会在崩溃中丢失。
- 如果设置为 2,则在每次事务提交后写入日志,并每秒刷新一次到磁盘。(提交后直接写入文件系统的page cache中,每秒刷新持久化到磁盘)未刷新日志的事务可能会在崩溃中丢失。
- 对于设置 0 和 2,不能 100% 保证每秒冲洗一次。由于DDL更改和其他内部InnoDB活动导致日志在InnoDB_flush_log_at_trx_commit设置下独立刷新,刷新的频率可能会更高,有时由于调度问题,刷新的频率会更低。如果日志每秒刷新一次,那么在崩溃中最多可能会丢失一秒钟的事务。如果刷新日志的频率高于或低于每秒一次,则可能丢失的事务量会相应变化。
- 日志刷新频率由控制
innodb_flush_log_at_timeout,它允许您将日志刷新频率设置为N秒(其中N是1 ... 2700,默认值为 1)。但是,任何意外的mysqld进程退出都可以擦除长达N几秒钟的事务。 - DDL 更改和其他内部
InnoDB活动刷新日志独立于innodb_flush_log_at_trx_commit设置。 - 无论innodb_flush_log_at_trx_commit设置如何,InnoDB崩溃恢复都可以工作。事务要么被完全应用,要么被完全删除。
为了在使用InnoDB处理事务的复制设置中保持持久性和一致性:
- 如果启用了二进制日志记录,请设置
sync_binlog=1。 - 始终设置
innodb_flush_log_at_trx_commit=1。
有关对意外停止最具弹性的副本上的设置组合的信息,请参阅 第 17.4.2 节,“处理副本的意外停止”。
小结
- innodb_flush_log_at_trx_commit默认为1,只能取0,1,2。
- 0和2的区别在于,0提交的时候还会停留在redo log buffer里比2危险,redo log buffer属于mysql进程所以在服务崩溃重启时候会丢失,所以一般不会用0。
- 从缓存持久化到磁盘的刷新频率由innodb_flush_log_at_timeout控制,间隔时间的设置需要根据服务器资源和丢失事务恢复/重试的工作做的是否完备等综合考虑。一般就使用默认值。
- 需要和复制保持严格的一致性和持久性可以同时设置:sync_binlog=1和innodb_flush_log_at_trx_commit=1。
上面有提到redo log buffer,接下来我们就行看看。
innodb_log_buffer_size
| 命令行格式 | --innodb-log-buffer-size=# |
| 系统变量 | innodb_log_buffer_size |
| 影响范围 | Global |
| 动态的 | Yes |
SET_VAR提示适用 | No |
| 类型 | Integer |
| 默认值 | 16777216 (16M) |
| 最小值 | 1048576(1M) |
| 最大值 | 4294967295 (4G) |
InnoDB 用于写入磁盘上日志文件 的缓冲区大小(以字节为单位) 。默认值为 16MB。大的log buffer使大型事务无需在事务提交之前将日志写入磁盘即可运行。因此,如果您有更新、插入或删除许多行的事务,则使日志缓冲区更大可以节省磁盘 I/O。有关相关信息,请参阅 内存配置和 第 8.5.4 节,“优化 InnoDB 重做日志”。有关一般 I/O 调整建议,请参阅第 8.5.8 节,“优化 InnoDB 磁盘 I/O”.
小结
- innodb_log_buffer_size用于在事务进行中时所有事务log缓存区大小的控制。大小的设置取决于服务器资源,当允许的情况下越大越节省磁盘IO。
- 当innodb log buffer占用空间快达到一半的时候,后台线程会主动进行写盘写入文件系统的page cache。
- 当并行事务提交的时候,如果设置了innodb_flush_log_at_trx_commit=1,在刷盘的时候会把还没提交的事务redo log也刷进去,这个是没有关系的,因为redo log本来就是二阶段提交有状态控制。
至于为啥并行事务提交的时候为啥也会把未提交事务的redo log也进行刷盘,是因为不会产生啥影响同时可以减少IO次数何乐而不为。
概述
从上面的配置,我们可以得出,Redo Log大致的写入流程:
- 先写入redo log buffer中。
- 事务提交后。如果innodb_flush_log_at_trx_commit=0,则继续停留在redo log buffer中,等待后台定时刷盘。如果innodb_flush_log_at_trx_commit=1,则提交后马上刷盘。如果innodb_flush_log_at_trx_commit=2,会进行写盘(写入文件系统的page cache中),等待后台定时刷盘。
从redo log buffer到page cache和持久化次磁盘不止受到innodb_flush_log_at_trx_commit配置的影响,还会因为空间不足和并发事务提交的影响。
区域如图:
总结
从上面对innodb_flush_log_at_trx_commit和innodb_log_buffer_size的介绍,我们已经大致知道Redo Log的写入流程:redo log buffer -> page cache -> fsync。至于具体具体策略可以通过设置innodb_flush_log_at_trx_commit和innodb_log_buffer_size进行调整。
使用
- innodb_flush_log_at_trx_commit:需要和复制保持严格的一致性和持久性可以同时设置——sync_binlog=1和innodb_flush_log_at_trx_commit=1,至于性能问题可以调整硬件等其他方式;如果不那么严格允许丢失或者丢失通过其他方式控制又想基于目前服务器资源进行优化,可以把innodb_flush_log_at_trx_commit=2,等待后台线程定时刷盘,定时时间一般使用默认的1就行,这样最多可能丢失1s内未刷盘的事务。
- innodb_log_buffer_size:根据服务器资源设置一个较大值就好。