mysql核心参数_MySQL核心参数含义的源码解析(2)

最后,生成最终的刷新建议。生成最终的刷新建议时,会考虑当前数据库的活跃日志量的大小,当前活跃日志比较少的时候,认为重做日志文件有足够可以使用的空间(以变量pct_for_lsn小于30为依据),则不需要考虑每个buffer pool 之间的脏页年龄分布不均的情况,每个buffer pool 刷新相同的数量,数量就刷新总量除以buffer pool的个数。如果活跃日志比较多(以变量pct_for_lsn大于等于30为依据),则需要考虑脏页的年龄在每个buffer pool的分布不同,每个buffer刷新不同的数量的脏页,老的脏页比较多的buffer pool instance刷新的数量也就多。

以上就是建议函数生成刷新建议时的计算流程,下面根据源码来分析如何具体考虑这些因素,以便让我们有非常直观的理解。

381ba4c4960be6412083656f6c907568.png

首先来计算平均值,前面已经有比较清楚的讲过,现在大家来简单地看一下这部分代码,主要请关注这个if条件:当循环次数达到innodb_flush_avg_loops时或者经历的时间达到该值时,才进行新的平均值的计算。因此,大家清楚了这个参数的含义,是用来指明隔多久计算一次平均值。平均值计算规则就是新平均速度=当前的平均速度+最近这段期间平均速度,再除以2 。

1daa3446302e9b3c40b89880dbdb6395.png

接下来这一段代码呢,是首先计算lsn的age, 也就是活跃日志量的大小,然后调用相关函数根据脏页百分比来计算io_capacity的百分比,用变量pct_for_dirty保存,然后根据活跃日志量的大小来计算io_capacity的百分比,用变量pct_for_lsn来保存,这个值后面会被是使用到,用来决定每个buffer pool是建议刷新相同的数量的脏页,还是刷新不同的数量。当pct_for_lsn<30的时候,建议每个buffer刷新相同数量的页面。否则,建议刷新不同数量的页面。

最后比较这两个变量的大小,大的值作为最终的io_capacity的百分比,用变量pct_total保存。接下来我们将来看看是如何具体跟据这两项来计算io_capacity的百分比的。

4c5cc9316ee9ea4f4d91f4b3c8bbd334.png

函数af_get_pct_for_dirty()的计算逻辑是:

首先获取缓存池的脏页百分比,然后根据这个值进行判断。

如果参数最大脏页百分比的低水位设置为0(默认值),当dirty_pct大于参数innodb_max_dirty_pages_pct,则返回100, 否则返回0 。

如果设置了最大脏页百分比的低水位,当脏页百分比超过该值时,则返回相应的比例。当脏页百分比越接近最大脏页百分比,返回比例越接近100。  否则为0。

f3d2f38acb6a2876b7832c54669dff02.png

再来看看根据lsn的age,即活跃日志量来计算io_capacity百分比的规则。

如果活跃日志量占日志文件大小的百分比小于参数innodb_adaptive_flushing_lwm,即自适应刷新的低水位,默认是10,则直接返回0。

如果没有设置自适应刷新参数innodb_adaptive_flushing_lwm,默认为on ,则需要等待活跃的日志量大于max_async_age的值,才会返回相应的百分比,否则返回0。可以简单的理解为,如果没有开启自适应刷新,则必须等待活跃日志量的过大,大到存在危害数据库的可用性风险时,才开始考虑基于活跃日志量的大小来进行脏页刷新。

如果开启了自适应刷新,活跃日志量所占百分比大于自适应刷新的低水位时(innodb_adaptive_flushing_lwm),返回相应的百分比。具体计算公式查看ppt上的内容。

83133ce9daa8ed8e7e6a6e50d601fb27.png

接下来,我们来看看是怎么根据重做日志的生成速度来计算每个buffer需要刷新多少脏页的。这一段代码,不涉及数据库的任何参数,代码的功能就是根据重做日志生产的速度,来计算每个buffer需要刷新多少页面以及所有buffer pool所建议刷新的总量,但这个不是最终的建议。

首先,根据前面计算得出的lsn_avg_rate,即重做日志产生的平均速度,计算出一个target_lsn号。

然后从每一个buffer pool的脏页列表的队尾开始取出脏页,将脏页的old_modifiaction(最小的lsn)跟target_lsn进行比较,这里简单的说明一下脏页的oldest_modification的含义,它表示的是脏页第一次修改时的lsn号,也就是脏页的最小lsn号。如果它小于target_lsn, 然后将其作为刷新对象进行计数,否则,退出这个buffer pool 内的循环.因为刷新列表时按照脏页的最小lsn号进行排序的,前面的脏页的最小lsn都大于target_lsn ,所以不需要再继续找下去。

从上面的计算方式可以看出,当重做日志生成的平均速度越大,target_lsn 就越大,同时,如果buffer_pool中的脏页的old_modition小于target_lsn的数量越多,也就是老的脏页越多,被建议刷新的页面就越多。

6a3864ecf6e0a10c5a90c3e912332bd1.png

这张ppt上一张ppt代码段的注释。

4a43745ec479884a249bb3b0382f198e.png

生成最终的刷新建议。

通过前面的计算,我们从不同维度分别得出三个建议刷新的数量,然后将这个三个值进行平均,得出了综合所有因素的一个刷新建议总量,由变量n_pages保存。

影响刷新总量的因素有:脏页的百分比,活跃日志量的大小,当前redo生成的平均速度,当前脏页刷新平均速度,以及脏页的age分布情况,以及参数innodb_io_capacity,innodb_io_capacity_max。

前面根据活跃日志量计算所得出的io_capacity的百分比的这个变量——pct_for_lsn,在这里再次被用到。当pct_for_lsn <30时,认为重做日志文件有足够的可用空间,不需要考虑脏页的年龄在buffer pool instance之间分布不均的情况,建议每个buffer刷新相同的数量,否则,需要考虑脏页的年龄分布情况,每个buffer pool instance 所建议刷新的脏页数量不同,老的脏页比较多的buffer pool会被建议刷新更多地数量。

上面就是完整的刷新建议函数的解析,里面涉及到一些相关参数的使用,不知道大家对涉及到参数是否已经了解。

e9c8a2ae5c0435345a59d684dd49b7c1.png

当生成刷新建议之后,就设置刷新请求事件,请求刷新线程进行脏页批量刷新。 函数pc_request特别简单。

1.  将所有bufferpool instances 的刷新状态设置为PAGE_CLEANER_STATE_REQUESTED,即申请刷新.

2.  通过设置事件,唤醒/触发page cleaner 线程调用pc_flush_slot函数来进行buffer pool的批量刷新。

7997a3a332f2d1736286e3bc1ebb783b.png

Page_cleaner线程收到刷新请求之后,进行批量刷新。函数为pc_flush_slot.

寻找一个状态为申请刷新的缓存池实例,然后选为刷新对象,将状态修改为flushing.。然后执行后面的刷新。

执行buf_flush_LRU_list函数进行LRU列表的刷新,

3.  执行buf_flush_do_batch批量刷新脏页列表,该buffer pool instance建议刷新的数量slot->n_pages_requested作为该函数参数值,也就是依据建议刷新的页面数来进行刷新。

fea725158ec2a85820ac502fd2d33976.png

于LRU列表的刷新的函数buf_flush_LRU_list将scan_depth 变量传递最终传递给buf_flush_LRU_list_batch 函数, 在通常情况下,可以简单的理解scan_depth的值来自于数据库参数innodb_lru_scan_deptch参数。 接下来看buf_flush_LRU_list_batch函数。

d41d57da4f8b40b6785a1f8a218a4480.png

我们来看这个函数的循环体,我们来看退出循环的条件,满足任何一个条件退出:

1.如果free列表的长度大于innodb_lru_scan_depth,则中止循环。

2.被替换(evict_count)+被刷新(count)的页面数最多为scan_depth,scan_deptch可以简单理解为等于innodb_lru_scan_depth.      在看看循环里面的内容:

如果是一个可替换的页,则执行函数buf_LRU_free_page,将从LRU列表中摘除,其加入free列表。evict_count++

如果是脏页,则调用函数buf_flush_page_and_try_neighbors进行刷新,刷新数量累计到count值。

由此我们可以看出innodb_lru_scan_depth参数,在此起非常关键的作用,实际上也直接影响了buffer bool instance中的free列表的长度。

799cd4451296a7e9eea78a9be30d3138.png

对于脏页列表批量刷新的函数。

slot->n_pages_requested:为之前介绍的刷新建议函数

page_cleaner_flush_pages_recommendation为该buffer pool instance所建议的需要刷新的页面的数量,实际刷新的页面并不一定等于该值。后面将详细介绍。这个值最终传递给buf_do_flush_list_batch函数的min_n参数。

a63009cc5937a190c54fd17587afdbd7.png

我们来看一下这个函数,该函数主要逻辑也是一个for循环,我们来看一下循序中止的条件:

直到 count  >= min_n 或者脏页列表为空。  即所刷新的page等于所建议的刷新数量,或者“脏”页列表为空。

因为page cleaner线程调用该函数做批量刷新的时候,lsn_limit 参数值为极大值,因此无需考虑page的oldest_modification。

d805f84c2051b5e886c31c9048f0ad6c.png

刷新协调函数的执行一个刷新循环的最后一步,等待所有buffer pool instance刷新的完成。

函数特别简单,就是设置事件等待,等待所有buffer pool instance刷新完成的事件触发。

刷新完成之后,然后开始下一轮循环,如果刷新在1秒之内完成,则刷新协调线程会有短暂的sleep才会发起下一次刷新。期望是1秒钟进行一次所有buffer pool instance的批量刷新。

当作者把实录写完,也跪了——原来有这么多内容,终于理解现场90%以上的听众没有听懂的原因了。

实录太长,有失误之处烦请留言指出,谢谢!

文章来自微信公众号:数据库随笔

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值