前言
InnoDB 使用多个后台线程来处理不同的任务,如刷新脏页、写入重做日志、合并插入缓冲区等。
后台线程
Master Thread
主线程:
- 负责执行后台任务,如刷新脏页到磁盘、合并插入缓冲区、清理 Undo 日志等。
- 确保数据的一致性和持久性。
工作原理:
- 主线程是 InnoDB 的核心线程,负责执行各种后台任务。
- 定期将脏页(已修改但未写入磁盘的页)刷新到磁盘,以确保数据的持久性。
- 合并插入缓冲区,优化二级索引的插入性能。
- 清理已提交事务的 Undo 日志,释放空间。
- 监控系统的整体状态,并根据需要触发其他线程的操作。
协作关系:
- 主线程与 IO 线程协作,确保 IO 操作的高效执行。
- 与清理线程和页面清理线程协作,确保数据一致性和空间管理。
主线程具有最高的线程优先级别。其内部由多个循环组成:主循环(loop)、后台循环(backgroup loop)、刷新循环(flush loop)、暂停循环(suspend loop)。主线程会根据数据库运行的状态在以上几个循环中进行切换。
主循环:
大部分操作都在这个循环中进行。其中有两大部分:每秒的操作、每10秒的操作:
每秒操作:
- 日志缓冲刷新到磁盘,即使这个事务还没有提交(总是)(所以可以看到即使大事务的提交时间也很短暂)
- 合并插入缓冲(可能)
- 至多刷新 100个 InnoDB 的缓冲池中的脏页到磁盘(可能)
- 如果当前没有用户活动,则切换到 backgroup loop(可能)
合并插入缓冲(Insert Buffer)并不是每秒都会发生。InnoDB 会判断前一秒内发生的 IO 次数是否小于 5次,如果小于5次,InnoDB 认为当前的IO压力很小,可以执行合并插入缓冲的操作。
每10秒操作:
- 刷新100个脏页到磁盘(可能)
- 合并至多5个插入缓冲(总是)
- 将日志缓冲刷新到磁盘(总是)
- 删除无用的 undo页(总是)
- 刷新100个或者10个脏页到磁盘(总是)
对于刷盘这种存在 IO 的操作,会判断当前系统是否有足够的磁盘IO能力(是否空闲),来决定是否进行刷盘,避免影响实际的业务行为。
IO Thread
IO 线程:
- 包括读线程和写线程,负责处理异步 IO 请求。
- 读线程用于预读数据页,写线程用于将脏页写入磁盘。
工作原理:
- IO 线程分为读线程和写线程,处理异步 IO 请求。
- 读线程负责预读数据页,提高查询性能。
- 写线程负责将脏页写入磁盘,确保数据的持久性。
协作关系:
- IO 线程与主线程和页面清理线程协作,优化 IO 操作。
- 通过异步 IO 提高系统的并发性能。
Purge Thread
清理线程:
- 清理线程负责删除已提交事务的 Undo 日志。
- 确保 Undo 表空间不会无限增长,释放不再需要的空间。
协作关系:
- 与主线程协作,确保事务日志的及时清理。
- 保持数据库的空间使用效率。
Page Cleaner Thread
工作原理:
- 专门用于刷新脏页到磁盘,减轻主线程的负担。
- 提高系统的 IO 性能,确保数据的及时持久化。
协作关系:
- 与主线程和 IO 线程协作,优化脏页的刷新操作。
- 提高系统的整体性能和响应速度。
Insert Buffer Thread
插入缓冲线程:
- 处理插入缓冲的合并操作,优化二级索引的插入性能。
- 减少直接写入磁盘的次数,提高插入操作的效率。
协作关系:
- 与主线程协作,确保插入缓冲的及时合并。
- 提高二级索引的插入性能,减少磁盘 IO。
读写操作
有了后台线程,并不意味着所有操作都是后台线程异步处理。读写操作结合了 同步 和 异步 操作,以优化性能和确保数据一致性。
读操作
同步读:
- 当一个查询请求数据页时,如果该页已经在缓冲池中,InnoDB 会直接从缓冲池中读取数据,这是一个同步操作。
- 如果数据页不在缓冲池中,InnoDB 会触发一个同步 IO 操作,将数据页从磁盘加载到缓冲池中。
异步预读:
-
InnoDB 使用异步预读技术来提高查询性能。当检测到顺序访问模式时,InnoDB 会提前异步加载后续数据页。
-
这种预读操作是异步的,允许系统在后台加载数据,而不阻塞当前的查询操作。
写操作
同步写:
- 当事务提交时,InnoDB 会将事务日志同步写入磁盘,以确保事务的持久性。这是一个同步操作,确保数据不会在系统崩溃时丢失。
异步写:
- InnoDB 使用缓冲池来缓存数据页的修改,修改后的页称为脏页。
- 脏页的写入通常是异步的,由后台线程(如页面清理线程)负责将这些脏页刷新到磁盘。
- 这种异步写操作提高了系统的写性能,因为它允许多个修改合并后再写入磁盘,减少了磁盘 IO