Innodb:如何计算异步/同步刷脏及checkpoint的临界范围

本文主要是记录Innodb在初始化日志子系统时,如何计算异步/同步刷脏或checkpoint的临界范围

代码分析基于MySQL 5.6.11

///////////////////////////////////////////////////////////////////////////////////////////////

相关配置为:

innodb_log_buffer_size=200M
innodb_log_file_size=1000M
innodb_log_files_in_group=4

innodb_flush_log_at_trx_commit = 1

innodb_thread_concurrency = 64

 

刷脏和做checkpoint的临界条件在系统启动初始化日志系统时即被确定了,backtrace 如下:

innobase_start_or_create_for_mysql

     ->log_group_init

2151                 log_group_init(0, i, srv_log_file_size * UNIV_PAGE_SIZE,

2152                                SRV_LOG_SPACE_FIRST_ID,

2153                                SRV_LOG_SPACE_FIRST_ID + 1);

 

                 ->log_calc_max_ages

                    

 

log_calc_max_ages:

 

1.计算当前redo log日志组的最大容纳LSN(log_group_get_capacity):

smallest_capacity =  (group->file_size – LOG_FILE_HDR_SIZE) * group->n_files = (innodb_log_file_size-4*512)*4 = 4194295808

 

smallest_capacity =  smallest_capacity – smallest_capacity / 10;  // 为了安全起见,保留10分之一的空间

 

2.检查在当前thread concurrency(srv_thread_concurrency)限制下,日志组是否拥有足够的空闲空间:

        free = LOG_CHECKPOINT_FREE_PER_THREAD * (10 + srv_thread_concurrency)+ LOG_CHECKPOINT_EXTRA_FREE =  (4*16384) * (10 + 64) + 8*16384 = 4980736

 

如果free > smallest_capacity /2的话,那么就会错误退出,表明innodb_log_file_size设的太小了。

否则,预留边界:

 margin = smallest_capacity – free;

 margin = margin – margin / 10  = 3392896943;

 

 

实际上margin的计算可以总结为:

margin = {

                            [ (innodb_log_file_size-LOG_FILE_HDR_SIZE) * innodb_log_files_in_group ] * (9/10) 

                            – 

                            [ LOG_CHECKPOINT_FREE_PER_THREAD * (10 + innodb_thread_concurrency) + LOG_CHECKPOINT_EXTRA_FREE]

               } * (9/10)

 

 

 

 

log_sys->log_group_capacity = smallest_capacity  =   3774866228;              

 

log_sys->max_modified_age_async = margin– margin / LOG_POOL_PREFLUSH_RATIO_ASYNC  =  margin * (7/8)  = 2968784826           //当lsn -buf_pool_get_oldest_modification()超过这个值时, 需要做异步刷脏页

 

log_sys->max_modified_age_sync = margin– margin / LOG_POOL_PREFLUSH_RATIO_SYNC    = margin *(15/16)    = 3180840885          //当lsn -buf_pool_get_oldest_modification()超过这个值时, 需要做同步刷脏页

 

log_sys->max_checkpoint_age_async = margin – margin

                / LOG_POOL_CHECKPOINT_RATIO_ASYNC           =   margin *(31/32) = 3286868914          //当lsn – last_checkpoint_lsn超过该值时,需要做一次异步checkpoint

 

log_sys->max_checkpoint_age = margin =  3392896943                                                                   //lsn – last_checkpoint_lsn不允许超过该值,否则需要做同步checkpoint

 

 

上面这几个变量,除了第一个之外,都是用于在函数log_checkpoint_margin中进行判断,log_sys->check_flush_or_checkpoint是判断是否flush/checkpoint的关键变量

 

主要判断逻辑如下:

 

1.如果log_sys->check_flush_or_checkpoint为false,直接返回,表明不需要flush或者checkpoint

 

2.找出当前所有buffer pool实例中最老的oldesrt_lsn,从每个bp->flush_list的尾部读取(log_buf_pool_get_oldest_modification())

 

3.如果log->lsn – oldest_lsn大于log_sys->max_modified_age_sync,表明需要做一次同步刷新,将lsn 推进到新的lsn位置(log_preflush_pool_modified_pages):

 LSN范围为:2 * (log->lsn – oldest_lsn – log_sys->max_modified_age_sync)  + oldest_lsn

 

             如果刷新失败,表明同时有别的线程也在刷脏,则将check_flush_or_checkpoint设置为TRUE,回到第一步

 

4.判断是否需要做checkpoint

checkpoint_age = log->lsn – log->last_checkpoint_lsn;

如果checkpoint_age > log_sys->max_checkpoint_age, 表示需要做一次同步checkpoint;

如果 log_sys->max_checkpoint_age_async  < checkpoint_age   <=  log_sys->max_checkpoint_age ,表示需要做一次异步的checkpoint,并设置log_sys->check_flush_or_checkpoint = false;

如果checkpoint_age  <=log_sys->max_checkpoint_age_async  ,则无需做checkpoint,并设置log_sys->check_flush_or_checkpoint = false;

 

checkpoint 调用函数log_checkpoint(checkpoint_sync, FALSE); 如果是同步checkpoint(checkpoint_sync为TRUE) 还要返回到第1步继续判断

 

另外,这几个变量在函数log_close中会被用到,它会去做一件重要的事情:设置log_sys->check_flush_or_checkpoint。

 

至于异步刷脏,log_sys->max_modified_age_async被封装在函数log_get_max_modified_age_async中, 被函数af_get_pct_for_lsn。显而易见,异步刷脏是由page cleaner线程来完成的。

在函数af_get_pct_for_lsn中,根据当前的LSN,计算需要以IO capacity的百分之几来刷脏

 

当当前lsn-buf_pool_get_oldest_modification()超过log_sys->max_modified_age_async时:

 

age = log_sys->lsn – buf_pool_get_oldest_modification()

lsn_age_factor = (age *100)/log_sys->max_modified_age_async )

 

返回值为:

pct =   [

                 (innodb_io_capacity_max/innodb_io_capacity) 

                 *

                 (lsn_age_factor * sqrt((double)lsn_age_factor))

          ] /7.5

 

 

另外,如果参数innodb_adaptive_flushing设置为OFF,且没有超过log_get_max_modified_age_async()的话,直接返回0

 

Page cleaner线程会同时根据LSN 和脏页比例来获取pct,并取其中的最大值。

时间: 2024-09-25 05:49:31

Innodb:如何计算异步/同步刷脏及checkpoint的临界范围的相关文章

MySQL · 源码分析 · InnoDB LRU List刷脏改进之路

之前的一篇内核月报MySQL · 引擎特性 · InnoDB Buffer Pool 中对InnoDB Buffer pool的整体进行了详细的介绍.文章已经提到了LRU List以及刷脏的工作原理.本篇文章着重从MySQL 5.7源码层面对LRU List刷脏的工作原理,以及Percona针对MySQL LRU Flush的一些性能问题所做的改进,进行一下分析. 在MySQL中,如果当前数据库需要操作的数据集比Buffer pool中的空闲页面大的话,当前Buffer pool中的数据页就必须

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所做的一些优化工作.

数据同步-C/S架构的数据库异步同步问题

问题描述 C/S架构的数据库异步同步问题 开发语言:C# 数据库:sql server 想实现功能: 把服务器上的数据库down到本地,客户端使用时操作本地数据库,固定时间或服务器数据库连通的情况下,将本地数据同步到服务器的数据库中. 目的:在服务器关闭.或断网情况下,可以保证客户端使用的稳定性. 希望大神们指点迷津,提供一些可行性方案,十分感谢! 解决方案 关键看你的业务需求. 比如说电子词典完全可以离线工作,在线更新词库. 但是银行卡pos刷卡就绝对不能离线工作. 没有什么一劳永逸的办法,你

MySQL数据库InnoDB引擎主从复制同步经验总结_Mysql

近期将公司的MySQL架构升级了,由原先的一主多从换成了DRBD+Heartbeat双主多从,正好手上有一个电子商务网站新项目也要上线了,用的是DRBD+Heartbeat双主一从,由于此过程还是有别于以前的MyISAM引擎的,所以这里也将其心得归纳总结了一下: 1)MySQL的replication过程是一个异步同步的过程,并非完全的主从同步,所以同步的过程中是有延迟的,如果做了读写分离的业务的话,建议也要监控此延迟时间: 2)MySQL的master与slave机器记得server-id要保

支持异步同步的分布式CommandBus MSMQ实现:支持Session传递、多实例处理

先上一张本文所描述的适用场景图 分布式场景,共3台server: 前端Server Order App Server Warehouse App Server 功能: 前端Server可以不停的发送Command到CommandBus,然后由CommandBus分配不 同的Command到各自的app server去处理. 前端Server可以只发送Command而不必等待Response 前端Server可以同步等待Response返回 MSMQ消息超过3.5M会自动转为网络共享方式传输消息

GCD之异步同步体会

前面的博文也有写到同步异步,可能是看他人的博文,自己没有实验,感觉理解不深,所以就敲了些代码比较一下串行.并行分别对应的同步.异步. 1.首先创建串行.并行线程队列 dispatch_queue_t serialqueue=dispatch_queue_create("serialqueue", DISPATCH_QUEUE_SERIAL);//串行线程队列 dispatch_queue_t concurrentqueue=dispatch_queue_create("con

在asp.net页面中使用异步同步rss

有的时候我们需要在网页里读取论坛的信息,在传统ASP的时候我们使用的是JS或者是IFRAME,这两种方式都不是很方便,而且对搜索引擎不友好.现在有了.Net,我们有了另一种方式. 要求:论坛需要提供RSS支持. 代码如下: #region task class //这是一个任务类,执行具体的任务 public class RssAsyncTask { private String _rssContent; private AsyncTaskDelegate _dlgt; private stri

MYSQL INNODB 如何计算B+树表的最大容量和行数

考虑表结构如下: create table testzh(id int  primary key auto_increment ,id2 int,id3 int); 插入数据: delimiter //  create procedure ins3()      begin     declare i int;      set i=0;      while i<10000 do          insert into testzh(id2,id3) values(FLOOR((RAND()

MySQL · 引擎特性 · InnoDB redo log漫游

前言 InnoDB 有两块非常重要的日志,一个是undo log,另外一个是redo log,前者用来保证事务的原子性以及InnoDB的MVCC,后者用来保证事务的持久性. 和大多数关系型数据库一样,InnoDB记录了对数据文件的物理更改,并保证总是日志先行,也就是所谓的WAL,即在持久化数据文件前,保证之前的redo日志已经写到磁盘. LSN(log sequence number) 用于记录日志序号,它是一个不断递增的 unsigned long long 类型整数.在 InnoDB 的日志