[MySQL 5.6] page cleaner线程的效率问题

最近在测试5.6.11的写性能,当我完成一项测试,关闭workload,习惯性设置innodb_max_dirty_pages_pct为0,然后等待脏页刷完再shutdown。

 

发现存在刷脏的抖动:

 

time      flushed    Innodb_data_written

11:49:57  3692        117.3m

11:49:58  1125        33.5m|

11:49:59  4187        134.6m

11:50:00  1241         35.0m

11:50:01  4076        127.4m

 

从pstack的采样结果来看,page cleaner线程频繁出现这样的backtrace。

buf_flush_page_cleaner_thread->page_cleaner_sleep_if_needed->os_thread_sleep

加了两个计数来监控,也发现page cleaner线程平均sleep时间过长(750,000 ms 左右)。

那么为什么会出现波动呢?

检查发现,机器上有一个heartbeat脚本每隔两秒钟更新一条记录。这会导致如下条件成立:

2385                 if (srv_check_activity(last_activity)

2386                     || buf_get_n_pending_read_ios()

2387                     || n_flushed == 0) {

2388                         page_cleaner_sleep_if_needed(next_loop_time);

2389                 }

 

srv_check_activity(last_activity) 为非0值。目前的判断太过粗糙了。一条简单的UPDATE 会造成page cleaner线程的巨大波动。

相应的问题,已经report到buglist上:http://bugs.mysql.com/bug.php?id=69174

好吧,对我而言办法比较土,临时的解决方案就是增加一个变量,来限制最大sleep时间,这样就可以获得一个平缓的刷脏频率:

time      flushed    Innodb_data_written

11:51:43   3971         120.6m

11:51:44   3987         124.6m

11:51:45   3859         124.6m

11:51:46   3992         121.0m

11:51:47   3855         120.7m

 

另外,当srv_check_activity(last_activity)返回非0值后,会走不同的逻辑:

2393                 if (srv_check_activity(last_activity)) {

2394                         last_activity = srv_get_activity_count();

2395

2396                         /* Flush pages from end of LRU if required */

2397                         n_flushed = buf_flush_LRU_tail();

2398

2399                         /* Flush pages from flush_list if required */

2400                         n_flushed += page_cleaner_flush_pages_if_needed();

 

buf_flush_LRU_tail() : 依次遍历每个Buffer pool instance,从LRU尾部开始扫描,直到第srv_LRU_scan_depth个page停止,按批次刷LRU,每次期望刷100个page(一个CHUNK), 每个Bp会轮srv_LRU_scan_depth/100次循环

这里存在的问题,Mark Callaghan Report在这个Bug上:http://bugs.mysql.com/bug.php?id=69170

每一个CHUNK的循环,都是从LRU的尾部开始的,因为这中间会去释放bp的Mutex。

这样问题就比较明显了,如果有很多脏页,例如,我们假设LRU上的都是脏页.从函数buf_flush_LRU_list_batch的逻辑我们可以知道

1.如果这个Page是脏的,不可以替换,将其IO-FIX,并分发IO请求

2.回到LRU尾部,跳过IO-FIX的page,发发现新的脏页,同样将其IO-FIX,并返回到LRU尾部。

可以看到这里时间复杂度是O(N*N).当然如果是快速存储设备,可能在回到LRU尾部重新扫描时,之前IOFIX的page已经完成了IO,因此可以直接放到FreeList上。因此快速存储设备最优可以到达O(N)

按照Inaam的说法,5.6.12对此会有优化,拭目以待。另外在5.6.12中,可能会有很多sleep被替换成condition wait,希望这些能对写负载有帮助。

时间: 2024-12-11 05:56:55

[MySQL 5.6] page cleaner线程的效率问题的相关文章

MySQL 5.7: Page Cleaner的刷脏问题

之前我已经写过一篇博客,讨论过在flush LRU_LIST/FLUSH_LIST时,5.7对其做的优化,总的来说,就是使用类似Hazard Pointer的方式,避免在flush的过程中重复扫描LIST,将时间复杂度从O(N*N)下降到了O(N).有兴趣的同学可以翻阅下这篇博客:http://mysqllover.com/?p=1031 本文的目的主要是补充下5.7目前所做的多个page cleaner的实现思路,社区相关的bug讨论,以及我近期对page cleaner所做的一些优化工作.

[MySQL 5.6] Innodb page cleaner线程刷新策略

这部分内容是从http://mysqllover.com/?p=512 剥离出来,原文中为了保持整洁,将这些内容删除.   有以下几个参数会影响到Page cleaner的行为:   innodb_lru_scan_depth innodb_adaptive_flushing_lwm innodb_max_dirty_pages_pct_lwm innodb_io_capacity_max innodb_flushing_avg_loops   在函数page_cleaner_flush_pag

MySQL · TokuDB · Cachetable 的工作线程和线程池

介绍 TokuDB也有类似InnoDB的buffer pool叫做cachetable,存储数据节点(包括叶节点和中间节点)和rollback段,本文中为了表达简单,叶节点,中间节点和rollback段统称数据节点.Cachetable是全局唯一的,它与MySQL实例存在一一对应的关系.TokuDB没有采用常见的BTREE(BTREE+,BTREE*)表示索引,而是采用Fractal Tree,简称FT.FT跟BTREE+类似,维护了一个树形的有序结构,中间节点存储pivot(TokuDB的中间

如何提高mysql大批量数据更新(update)的效率?

问题描述 如何提高mysql大批量数据更新(update)的效率? 本人所写的sql语句如下: UPDATE resulttmpSET result.forward_count=ROUND(tmp.fca_s) result.comment_count=ROUND(tmp.cca_s) result.like_count=ROUND(tmp.lca_s)WHERE result.uid=tmp.uid; 两个表的数据都达到了一百万条,该语句执行起来非常慢,故请问各位,如何提高update效率.

mysql 插入10万条数据 优化效率

问题描述 mysql 插入10万条数据 优化效率 public int addTypes(List<taobaoBean> babyList) { String sql = "insert into type (typeid,url) values (?,?) "; Connection conn = dbhelper.getConnection(driver,url,username,upwd); int result = 0; PreparedStatement stm

根据mysql慢日志监控SQL语句执行效率_Mysql

根据mysql慢日志监控SQL语句执行效率 启用MySQL的log-slow-queries(慢查询记录). 在Linux环境下先要找到my.cnf文件(一般在/etc/mysql/),然后可能会发现该文件修改后无法保存,原因是你没有相应的权限,可以从属性中看到该文件的所有者是root,这时要先以root的身份打开它: sudo nautilus /etc/mysql 接着再打开my.cnf文件然后找到[mysqld]标签在下面加上: log-slow-queries=/path/slow.lo

mysql中使用UDF自动同步memcached效率笔记_Mysql

接上篇:mysql使用mysql-udf-http效率测试笔记 ,这次不使用rest架构,而是使用:libmemcached和memcached_functions_mysql,测试版本是: libmemcached-0.34.tar.gz和memcached_functions_mysql-0.9.tar.gz,其它版本配对都有问题,我安装测试过有问题的版本有: 复制代码 代码如下: memcached_functions_mysql-1.1在: libmemcached-0.49\libme

mysql 数据库查询随机数量条目的效率问题及解决办法

最近由于需要大概研究了一下MYSQL的随机抽取实现方法.举个例子,要从tablename表中随机提取一条记录,大家一般的写法就是:SELECT * FROM tablename ORDER BY RAND() LIMIT 1. 但是,后来我查了一下MYSQL的官方手册,里面针对RAND()的提示大概意思就是,在ORDER BY从句里面不能使用RAND()函数,因为这样会导致数据列被多次扫描.但是在MYSQL 3.23版本中,仍然可以通过ORDER BY RAND()来实现随机. 但是真正测试一下

mysql中提高Order by语句查询效率的两个思路分析_Mysql

因为可能需要对数据库的记录进行重新排序.在这篇文章中,笔者就谈谈提高Order By语句查询效率的两个思路,以供大家参考. 在MySQL数据库中,Order by语句的使用频率是比较高的.但是众所周知,在使用这个语句时,往往会降低数据查询的性能.因为可能需要对数据库的记录进行重新排序.在这篇文章中,笔者就谈谈提高Order By语句查询效率的两个思路,以供大家参考. 498)this.width=498;" border=0>  一.建议使用一个索引来满足Order By子句. 在条件允许