回顾
InnoDB 1.0.x之前的Master Thread
Master Thread是InnoDB中线程优先级最高的线程。它的内部有多个轮询的方法:
- 主循环loop.
- 后台循环background loop.
- 刷新循环flush loop.
- 暂停循环suspend loop.
主循环 Loop
Loop被称为主循环,也就是大部分的工作都发生在这个循环中。它有两大部分的行为:
- every second(每秒).
- every 10 seconds(每10秒).
以下用java伪代码来描述这个行为
public static void masterThread() throws InterruptedException {
while (true) {
for (int i = 0; i < 10; i++) {
//每秒需要执行的任务,详细信息看下面解析
syncFlushRedoLogToDisk();
if(lastOneSecondIOs < 5){
mergeMostFiveInsertBuffer();
}
if(buf_get_modified_ratio_pct > innodb_max_dirty_pages_pct){
flushDirtyPages(100);
}
if(userActivity.size() = 0){
backgroundLoop();
}
//如果有必要,那么睡眠 1S
if (isNecessary) {
Thread.sleep(1000);
}
}
// 每10秒需要执行的任务
}
}
每秒需要做的操作
- 日志缓冲刷新到磁盘,即使当前事务没有提交(always).
- 合并插入缓冲(maybe).
- 至多刷新100个InnoDB的缓冲池中的脏页到磁盘(maybe).
- 如果当前没有用户活动,则切换到background loop(maybe).
每10秒需要做的操作
- 刷新100个脏页到磁盘(maybe).
- 合并最多5个插入缓冲(always).
- 将日志缓冲刷新到磁盘(always).
- 删除无用的Undo页(always).
- 刷新100个或者10个脏页到磁盘(always).
public static void masterThread() throws InterruptedException {
while (true) {
for (int i = 0; i < 10; i++) {
// 每秒需要执行的任务
// 将日志信息刷新到磁盘
syncFlushRedoLogToDisk();
// 如果上一秒发生的IO大于5,则执行插入缓冲合并
if (lastOneSecondIOs < 5) {
mergeMostFiveInsertBuffer();
}
// 如果当前脏页比例超过90%,刷新100个脏页到磁盘
if (buf_get_modified_ratio_pct > innodb_max_dirty_pages_pct) {
flushDirtyPages(100);
}
// 如果当前没有用户活动,进入backgroundLoop
if (userActivity.size() = 0) {
backgroundLoop();
}
//如果有必要,那么睡眠 1S
if (isNecessary) {
Thread.sleep(1000);
}
}
// 每10秒需要执行的任务
// 如果上一秒发生的IO大于200
if (lastOneSecondIOs < 200) {
// 刷新100个脏页到磁盘
flushDirtyPages(100);
}
// 合并插入缓冲
mergeMostFiveInsertBuffer();
// 将日志信息刷新到磁盘
syncFlushRedoLogToDisk();
// 回收无用的undo页
fullPurge();
// 如果脏页比例>70%
if (buf_get_modified_ratio_pct > 0.7) {
// 刷新100个脏页到磁盘
flushDirtyPages(100);
} else {
// 刷新10个脏页到磁盘
flushDirtyPages(10);
}
// 如果当前没有用户活动,进入backgroundLoop
if (userActivity.size() = 0) {
backgroundLoop();
}
}
}
background loop
如果当前没有用户活动(数据库空闲时间)或者数据库关闭(shutdown),就会切换到这个循环。它执行的操作为:
- 删除无用的Undo页(always).
- 合并20个插入缓冲(always).
- 不断刷新100个页直到符合条件(可能,跳转到flush loop中完成).
- 跳回到主循环(always).
InnoDB 1.2.x之前的缺陷
- 对IO有限制。从解析中可以看到,刷新脏页数等都是固定死的参数,无法适配当前磁盘的发展。当前的SSD固态磁盘写入的性能得到了很好的改善,但是由于hard coding,这无法得到较好的配置。
- innodb_max_dirty_pages_pct的默认值过大,想象一下你有90%的衣服没洗你才去洗衣服,这是多么悲催的事情。因此不要堆积过多的未完成事项。
InnoDB对此做出的优化-innodb_io_capacity和innodb_max_dirty_pages_pct.
innodb_io_capacity:
解决这种写死参数的方法很简单,就是把它做出配置项,动态注入到代码中即可,对此,InnoDB提供了innodb_io_capacity
让用户来对IO进行控制。默认值为200,它表示磁盘的IO吞吐量为200.
配置:
合并缓冲大小 = innodb_io_capacity * 5;
刷新脏页数量 = innodb_io_capacity;
如果你使用的是SSD的磁盘获取将部分磁盘做了RAID,也就是你的磁盘拥有更高的IO速度时,可以放心把innodb_io_capacity调大一些,直到符合磁盘的IO吞吐量为止。
innodb_max_dirty_pages_pct:
调整的过小也是不好的,这样会频繁地发生刷新脏页的IO操作。InnoDB官方设定的是75%,谷歌得出的结论是80%.这样,脏页的刷新频率得到了相应的提升,磁盘IO负载也得到了保证。
innodb_purge_batch_size
这个简单提一下,这是一个可以控制Undo页回收数量的参数,有需要可以进行调整。
InnoDB 1.2.X版本的Master Thread
InnoDB引入了Page Cleaner Thread.把刷新脏页的操作交给它来执行。这样减轻了Master Thread的工作,同时进一步提高了系统的并发性。