MySQL 8.0重做日志写入机制改为无锁并发写入,采用双队列模型(prepare/flush)、可变长记录+CRC校验,刷盘更频繁严格,对NVMe SSD低延迟(

MySQL 8.0重做日志写入机制变了
MySQL 8.0 默认启用 innodb_redo_log_encrypt=OFF 但底层日志写入路径更严格、更频繁,尤其在事务提交时强制刷盘(innodb_flush_log_at_trx_commit=1 下每事务一次 fsync)。相比 5.7,8.0 的重做日志格式改为可变长度记录 + 元数据校验块,写入前需额外序列化和 CRC 计算,CPU 和 I/O 路径都变长了。
关键变化点:
- 日志缓冲区(
innodb_log_buffer_size)默认值未变(16MB),但高并发小事务场景下更容易触发提前刷盘 - 重做日志文件组(
innodb_redo_log_capacity)取代旧版innodb_log_file_size × innodb_log_files_in_group,容量计算更刚性,扩容需停机或在线调整(8.0.30+) - 日志写入线程从单线程变为双队列模型(prepare queue + flush queue),对磁盘随机写延迟更敏感
SSD不是“够用就行”,而是“必须匹配I/O特征”
MySQL 8.0 对 SSD 的要求不再是“有就行”,而是要看它能否扛住重做日志的写入模式:小块(通常 512B–4KB)、顺序追加但需低延迟 fsync。NVMe SSD 的 sync_write_latency 若超过 2ms,就可能在高并发下堆积日志写请求,引发 Waiting for handler commit 状态蔓延。
常见误判:
- 用 SATA SSD 当作“高性能替代”——其
fsync延迟常达 5–15ms,远高于 NVMe 的 0.1–0.5ms - 忽略队列深度(
nvme list查Queue Depth),低队列深度 SSD 在并发写日志时吞吐骤降 - RAID 0 下未禁用
innodb_flush_neighbors=0,导致 SSD 内部垃圾回收被干扰
innodb_use_native_aio 开启反而卡死?看Linux内核版本
MySQL 8.0 默认开启 innodb_use_native_aio=ON,依赖 Linux 的 io_setup() 系统调用。但在内核 [ERROR] InnoDB: Error: io_setup() failed with EAGAIN after 5 attempts。
实操建议:
- 确认内核版本:
uname -r;若 innodb_use_native_aio=0 - 若必须开 AIO,需同时配
innodb_io_capacity≥ 2000(NVMe)或 ≥ 500(SATA SSD),否则 AIO 队列空转 - 避免混用:
innodb_use_native_aio=1+sync_binlog=1+innodb_flush_log_at_trx_commit=1,三者叠加会放大 I/O 尖峰
重做日志 I/O 瓶颈的典型错误日志信号
别等服务挂了才查,这些日志出现就要立刻干预:
-
[FATAL] InnoDB: fsync() returned EIO, aborting.→ 磁盘硬件故障或文件系统只读,立即dmesg | tail查 SCSI/NVMe 错误 -
[ERROR] [FATAL] InnoDB: Semaphore wait has lasted > 600 seconds.→ 大概率是重做日志刷盘卡住,检查iostat -x 1中%util是否持续 100%、await> 10ms -
SHOW ENGINE INNODB STATUS里LOG段显示Log sequence number远超Log flushed up to→ 日志写入滞后,说明innodb_log_writer_threads或磁盘跟不上
真正难处理的,是那些没报错但 innodb_redo_log_evicted_bytes 持续增长的场景——这意味着日志空间反复回收,背后是写入吞吐已逼近设备物理极限,此时换盘比调参更有效。


















