Mysql进程模型是单进程多线程,所以我们通过ps查找mysqld进程时只有一个。
线程简介
默认情况下InnoDB默认引擎的后台线程有7个——4个IO线程(insert buffer thread、log thread、read thread、write thread,InnoDB Plugin版本将读写线程增加到了各4个),1个master线程,1个锁监控线程,1个错误监控线程。
线程源码
master thread
master thread优先级别最高,内部由几个循环组成:主循环(loop)、后台循环(background loop)、刷新循环(flush loop)、暂停循环(suspend loop)
Loop
主循环主要有两大方面的任务,这两大方面得任务分别1s执行一次和10s执行一次
每秒一次的操作:
- 日志缓冲(log buffer)刷新到磁盘,即使这个事务还没有提交。(总是)
- 合并插入缓冲(可能):
每秒IO次数小于5,则执行合并插入操作。 - 至多刷新100个InnoDB脏页到磁盘(可能):
判断当前缓冲池中脏页的比例是否查过了配置文件中的参数(innodb_max_dirty_pages_pct,默认为90%),如果超过则,则将100个脏页写入磁盘。 - 如果当前没有用户活动,切换到background loop(可能)
什么是插入缓冲(insert buffer)? 插入缓冲是为了更高效的插入而设计,对非聚簇非唯一索引更有效。当插入或更新时,不直接插入索引页,而是先判断该非聚集索引页是否在缓冲池中,如果在直接插入,如果不再,则先放入一个插入缓冲区中,然后以一定的频率执行插入缓冲池和非聚簇索引合并的操作。 为什么插入缓冲需要非聚簇非唯一索引呢? 聚簇索引一般是顺序的,并不需要磁盘随机读写。 如果是唯一索引,那么我们在插入前需要先查询是否满足唯一,这样不仅没有减少IO操作,反而增大了IO操作。
每10秒一次的操作:
- 刷新100个脏页到磁盘(可能):
过去10秒内IO操作次数小于200次,则执行刷新100个脏页到磁盘。 - 合并至多5个插入缓冲(总是)
- 将日志缓冲刷新到磁盘(总是)
- 删除无用的Undo页(总是):
对表执行update、delete操作时,原先的行被标记为删除,在full purge过程中,InnoDB存储引擎会判断当前事务系统中的已被删除的行是否可以删除,如果可以InnoDB立即将其删除。 - 刷新100个或者10个脏页到磁盘(总是):
判断缓冲池中脏页的比例,如果超过70%,则刷新100个脏页到磁盘,如果脏页比例小于70%,则只需刷新10%的脏页到磁盘。 -
Background Loop
删除无用的Undo页(总是)
- 合并20个插入缓冲(总是)
- 跳回到主循环(藏式)
- 不断刷新100个页,直到符合条件(可能)
查看当前线程状态
show engine innodb status\G;
潜在问题
innodb引擎对IO其实是做了一些hard code,比如每秒钟InnoDB最多只会刷新100个脏页到磁盘、合并20个插入缓冲,如果是在密集写入的程序中,引擎可能会忙不过来。
