mysql io队列_网易视频云经验分享MYSQL 5.5 的IO控制

网易视频云是网易倾力打造的一款基于云计算的分布式多媒体处理集群和专业音视频技术,为客户提供稳定流畅、低时延、高并发的视频直播、录制、存储、转码及点播等音视频的PASS服务。在线教育、远程医疗、娱乐秀场、在线金融等各行业及企业用户只需经过简单的开发即可打造在线音视频平台。现在,网易视频云与大家分享一下MYSQL 5.5的IO控制简单分析

IO算法对于数据库的性能有着非常直接的影响,当数据库的页面(data,undo)不能完全存放于系统页缓存时,就会有读IO,而系统检查点,以及LRU链表的替换会发起写页面操作,而事务提交刷日志、数据段扩展等等也会有IO产生,各个IO相互影响相互制约。本文简单剖析MYSQL Innodb是如何权衡各个IO的。由于5.1版本比较古老,并且5.5和刚发布的5.6对IO模块有较大改动,因此选取了5.5.22做简单分析。

MYSQL -5.5.22:

INNODB将buffer中的页面写入文件中有两种操作Type:

1.BUF_FLUSH_LRU 将LRU链表尾部的页面刷出

2.BUF_FLUSH_LIST 将FLUSH LIST 尾部的页面刷出

1 类型是由前台线程触发(注:INNODB的LRUFLUSH页面后会将页面放到freeList中,下次由前台线程直接调用,不需要去LRU链表中找替换),调用buf_flush_free_margin->buf_flush_LRU->buf_flush_batch->buf_flush_LRU_list_batch 方法,此方法有一个参数是min_n代表期望至少要刷多少个页面(实际值未必能达到),这个值的计算方法在buf_flush_LRU_recommendation方法中,因此如何控制IO量就需要看懂这个方法:

首先明确几个参数:

BUF_READ_AHEAD_AREA: 确定read-ahead算法读取几个页面,取64 和当前buffersize除以32后最近的2的幂数中的最小值

BUF_LRU_FREE_SEARCH_LEN:LRU FLUSH中至少寻找几个页面,取两倍的BUF_READ_AHEAD_AREA加5

BUF_FLUSH_FREE_BLOCK_MARGIN:当buf_flush_free_margin被调用时尝试将这些数量的页面在freelist和LRUlist中被替换。取BUF_READ_AHEAD_AREA加5

BUF_FLUSH_EXTRA_MARGIN:BUF_FLUSH_FREE_BLOCK_MARGIN之上额外的MARGIN。取BUF_FLUSH_FREE_BLOCK_MARGIN除以4加100,再除以bufpoolinstance的个数

主要的流程为:

1.得到bufpool 的freelist长度 n_replaceable

2.得到LRU尾部的页面bPage

3.循环:当bPage不为NULL,并且n_replaceable 小于freeBlockMargin与FlushExtraMargin之和,并且distant小于LRUFREE SEARCH LEN

a)如果bPage已经准备好被替换,那么n_replaceable++

i.判断是否准备好被替换的条件是:

1.该bPage可以映射到文件

2.bPage的Oldest_modification 中记录的lsn为0

3.bPage的io_fix state为BUF_IO_NONE

4.bPage的buf_fix_count(pin)为0

b)Distance++

c)bPage指向LRU中前一个页面

4.如果n_replaceable大于BUF_FLUSH_FREE_BLOCK_MARGIN,则返回0

5.返回BUF_FLUSH_FREE_BLOCK_MARGIN加上BUF_FLUSH_EXTRA_MARGIN减去n_replaceable

buf_flush_LRU_list_batch流程:

1.    循环:从LRU链表尾部开始搜寻可以flush的页面,只要bPage不为空,并且搜索长度小于传入的min_n值。

2       调用buf_flush_page_and_try_neighbors->buf_flush_try_neighbors

a. 如果LRU链表过短,则除了LRU尾端的页面不刷

b. 刷页面的区间为BUF_READ_AHEAD_AREA 和bufpool当前size的1/16的最小值

c. 循环:刷写范围内的所有脏页(包括neighbor)

I.       如果此脏页不在old区要跳过

II.     如果是neighbors页面,那么buf_fix_count(pin)必须为0才刷出(为了防止semaphorewaits,这里和具体的io实现有关,semaphore waits等待之前要刷double writer)

此处一个不妥的地方是,INNODB的try Neighbors 是会将一个范围内所有的脏页都认为是邻居页面,但是这些脏页未必是物理连续的,那也就和刷页面顺带把相邻页面一起刷出的初衷有出入,percona改进了此点,详情以及测试效果可以见

http://www.mysqlperformanceblog.com/2012/01/17/benchmarks-of-new-innodb_flush_neighbor_pages/

2类型是由master线程触发,调用buf_flush_list 方法,该方法有两个参数,一个是min_n至少要刷出的脏页数量(实际可能达不到),另一个参数是lsn_limit? 至少将页面old modification小于这个值的脏页给刷出:

1.            Masterthread 会在有前台活动时进入LOOP中循环10次调用:

a)当bufpool中超过75%的页面被修改时,会以100%IO能力刷一次FllushList(默认刷两百个页面)

b)      如果脏页在75%以下,并且启用Adaptiveflushing(为了保证redolog不会在检查点时爆炸,更加平稳)刷的页面数量根据buf_Flush_get_desired_flush_rate 得到(由log生成情况计算得到)

a. 获取日志组的日志容量和所有bufpool的flushlist长度(脏页)总和

b. 得到平均日志量:从buf_flush_stat_sum统计信息中获取每秒产生的redo加上当前系统lsn减去buf_flush_stat_cur统计中的redo量

c. 得到LRU平均刷脏页量:从buf_flush_stat_sum统计信息中获取每秒刷的脏页量加上系统非flushlist刷的脏页减去buf_flush_stat_cur统计中的刷脏页量

d. 得到以日志量计算的刷脏页总和:脏页总和乘以平均日志量除以日志组容量

e. 将刷脏页总和减去LRU刷脏页数,得到flushList要刷的脏页数

将IO量100%和这个计算出来的脏页量的较小值传递给buf_flush_list方法

其中进入这10次循环尽量做到每次循环持续1秒。如果发现没有前台线程活动,则进入background循环

这10秒之后:

获取系统pendIO:bufpool的pending着的页面IO总和加上日志系统的pendingIO总和

获取系统IO:bufpool的读写io总和与日志系统的io总和

如果pendIO小于3%系统io能力,并且10次循环中的系统IO增量小于200%的系统IO认为磁盘还有剩余的IO能力,那么再以100%的系统IO调用一次buf_flush_list

之后masterthread会做fuzzy检查点

如果脏页超过bufpool的70%,以100%系统IO调用一次buf_flush_list,否则以10%系统IO调用一次buf_flush_list

进入background循环后进入flush循环,当系统关闭 fastshutdown参数小于2时要以100%系统IO能力刷脏页

2.log_preflush_pool_modified_pages会刷脏页

3.recv_apply_hashed_log_recs会刷脏页

(这两个都是在恢复过程中刷脏页,不在主流程中,因此暂不讨论)

5.5.22中刷脏页的统计信息的获取,flush相关的统计信息由后台线程srv_error_monitor_thread进行收集,由于是保留了前20秒的信息,因此mysql是实现了一个流式队列,当得到下一秒的信息后将替换20秒前的统计信息。

实际的写脏页在buf_flush_list的实现:需要先将doublewritememory中的内容刷到硬盘中,然后调用buf_flush_write_block_low方法刷页面,其中的核心是fil_io方法,里面通过不同参数控制是读写,操作页面的类型(数据、日志、Ibuf等)将页面发往不同的异步IO队列等待IO完成。具体不细展开。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值