这是《MySQL 8.0 源码与内核实战》的独立章节版。本章从概念、实操和生产排查三个视角展开,代码块保留了原书可直接运行的版本。 InnoDB 的稳定运行依赖后台线程:刷脏、purge、IO、日志、统计和监控。它们决定写入平滑性、恢复速度和延迟抖动。
22.1 线程全景
| 线程 | 职责 |
|---|---|
| master thread | 协调后台任务 |
| page cleaner | 刷脏页 |
| purge coordinator/worker | 清理 undo |
| log writer/flusher/checkpointer | redo 链路 |
| read ahead / aio | 异步 IO |
| dict stats | 统计采集 |
| monitor thread | 周期检查 |
查看:
SELECT NAME, TYPE, PROCESSLIST_INFO
FROM performance_schema.threads
WHERE NAME LIKE '%innodb%';
22.2 Page Cleaner
dirty page pressure
-> calculate target
-> choose pages from LRU/flush list
-> doublewrite
-> write data files
目标:
- 控制脏页比例;
- 推进 checkpoint;
- 保留干净页;
- 避免用户线程大量 flush;
- 平滑 IO。
参数:
SHOW VARIABLES LIKE 'innodb_page_cleaners';
SHOW VARIABLES LIKE 'innodb_io_capacity%';
SHOW VARIABLES LIKE 'innodb_max_dirty_pages_pct%';
22.3 IO 线程
SHOW VARIABLES LIKE 'innodb_read_io_threads';
SHOW VARIABLES LIKE 'innodb_write_io_threads';
关注随机读、顺序预读、脏页写入、异步排队和设备队列深度。云盘与本地 NVMe 差异明显,应以压测为准。
22.4 日志线程
8.0.30 及以后版本使用 innodb_redo_log_capacity 管理 redo 容量;早期 8.0 使用 innodb_log_file_size 与 innodb_log_files_in_group。
日志链路:
log buffer
-> writer
-> flusher
-> write notifier
-> checkpointer
22.5 观测
SELECT event_name, count_star, sum_timer_wait
FROM performance_schema.events_waits_summary_global_by_event_name
WHERE event_name LIKE 'wait/io/innodb%'
ORDER BY sum_timer_wait DESC;
22.6 常见故障
| 现象 | 排查 |
|---|---|
| 写入尖刺 | checkpoint、purge、脏页 |
| IO 队列高 | io threads、设备能力 |
| CPU 单核高 | 单模块锁或单线程瓶颈 |
| history list 高 | 长事务 |
| shutdown 慢 | 刷脏和 purge |
| 恢复慢 | redo、脏页、大事务 |
本章小结
后台线程承担 InnoDB 的刷脏、清理、日志和 IO 工作。调优要围绕压力来源,而不是只改线程数;观测应同时看状态、等待和操作系统 IO。
思考题
- page cleaner 如何降低用户线程 flush?
- redo 容量参数在 8.0 版本间有什么差异?
- IO 线程数是否越大越好?
- 写入尖刺常见来源有哪些?
- 如何区分 InnoDB 内部等待和操作系统 IO 压力?