[MySQL 5.6] Innodb后台线程之master线程

在MySQL 5.6中,master线程的工作已经被大大减轻,类似purge, page clean都分配给独立的后台线程来进行。那么现在master线程还需要干啥活儿呢。以下就是本文需要介绍的部分

简单的看看代码,函数入口不变,依旧是srv_master_thread,但相对5.5的代码,这里已经非常非常精简了。
概括的说,master线程干这么几件事儿:
A. 每sleep 1秒钟
检查最近1秒内是否有活跃事件,这是一个全局计数器,在几个地方会被递增(通过函数srv_inc_activity_count):
1.srv_active_wake_master_thread—> 实际上在5.6里这里只剩下计数器的功能了,因为除非是以force recovery 启动,或者被shutdown了,否则不会进入suspend状态
2.srv_wake_master_thread—> 在DROP/TRUNCATE TABLE时会调用到,实际上 ,在5.6的代码里,master线程大多是在sleep的状态,并不需要去做wake up的动作(report了一个bug:http://bugs.mysql.com/bug.php?id=69270
3.row_undo_step->事务回滚时
例如事务提交/prepare时(innobase_commit->srv_active_wake_master_thread) ,事务回滚时,一个简单的查询都会引起计数器增加,从而让Master线程判定现在系统正忙.
A.1如果认定现在系统正忙,则调用函数srv_master_do_active_tasks,做如下工作:
1.log_free_check
总会检查redo中是否有足够的空间,以确定是否做flush或者做checkpoint,通常情况下,用户线程在写redo日志之前也会无条件调用该函数。
这里会先在无加锁的情况下,检查log_sys->check_flush_or_checkpoint是否为TRUE,如果为TRUE,则调用log_check_margins(),否则直接返回。
check_flush_or_checkpoint在函数log_close中被设置,backtrace如下:
      mtr_commit->mtr_log_reserve_and_write->log_close()
在每次将一个mtr日志写到buffer后,总会调用log_close()函数,注意,该函数是持有log_sys->mutex锁的
有以下几种情况会去设置check_flush_or_checkpoint为TRUE:
    • log_sys->buf_free > log_sys->max_buf_free
    • log_sys->lsn-buf_pool_get_oldest_modification() >log_sys->max_modified_age_sync
    • log_sys->lsn-log_sys->last_checkpoint_lsn > log_sys->max_checkpoint_age_async
TODO: mtr的组织,如何提交,以及redo 日志在内存中的控制
log_free_check会调用log_check_margins做两件事:
1)调用log_flush_margin:首先确认log->buf_free 是否大于 log->max_buf_free,如果是,则需要将日志写到文件,到当前lsn(log_write_up_to(lsn, LOG_NO_WAIT, FALSE))。如果已经有别的线程在干这活儿,则啥也不干,返回
2)调用log_checkpoint_margin,判断是否达到redo的同步刷脏点,或者异步/同步checkpoint点,决定是否刷脏(log_preflush_pool_modified_pages)及做checkpoint(log_checkpoint)
3)如果log_sys->check_flush_or_checkpoint依然为TRUE,则回到1)继续。


2.ibuf_contract_in_background(0, FALSE);
做ibuf merge, 正常情况下,每次处理innodb_io_capacity*0.05个page,
但如果ibuf->size > ibuf->max_size / 2,则处理:
n_pages = innodb_io_capacity   *   { [((ibuf->size – ibuf->max_size / 2)*100)/(ibuf->max_size + 1)]/100 }
这种情况说明change buffer太多了,需要合并更多的page
3.srv_sync_log_buffer_in_background();
如果需要的话,sync日志到磁盘
master线程通过该函数确保每隔一段时间,刷一次redo日志到磁盘log_buffer_sync_in_background(TRUE)->log_write_up_to(log_sys->lsn, LOG_NO_WAIT, TRUE)
时间间隔由innodb_flush_log_at_timeout来控制,单位为秒。
根据文档的解释,innodb_flush_log_at_timeout只有在innodb_flush_log_at_trx_commit值为2时才生效,但事实上,不管inndob_flush_log_at_trx_commit设为何值,都会调用log_buffer_sync_in_background
TODO:需要检查,如果innodb_flush_log_at_trx_commit设为1时,是否还需要调用srv_sync_log_buffer_in_background()函数
4.如果打开了MEM_PERIODIC_CHECK宏(默认关闭),则每隔13秒,检查是否出现内存损坏(mem_validate_all_blocks)
5.每隔47秒(SRV_MASTER_DICT_LRU_INTERVAL)检查一次dict cache。
srv_master_evict_from_table_cache(50)
需要持有dict_operation_lock的x锁,以及dict_sys->mutex
dict_make_room_in_cache :最大允许的table cache大小由table_definition_cache来决定
> 如果当前dict_sys->table_LRU的长度尚小于table_definition_cache,无需检测,直接返回
>否则,从table_LRU尾部开始,对于可以驱逐的表(dict_table_remove_from_cache_low),从dict cache中移除(dict_table_remove_from_cache_low),直到检测长度超过pct_check(这里是50%)或者dict cache长度<=table_definition_cache停止扫描
满足如下条件的表可以被从dict cache中驱逐:
1.当前没有被任何事务引用(table->n_ref_count = 0 )
2.该表上没有表锁或和录锁(table->locks) ==  0  &&  table->n_rec_locks == 0)
3.表上的索引没有被adaptive hash index引用(index->search_info->ref_count 为0)
这也是5.6的一点优化,主要是防止数据词典过大导致太大的内存消耗.如果内存对你而言不是问题,那就尽量调大table_definition_cache吧。
6.每隔7秒(SRV_MASTER_CHECKPOINT_INTERVAL)做一次新的checkpoint
log_checkpoint(TRUE, FALSE); 
A.2如果认定现在系统正处于空闲,则调用函数srv_master_do_idle_tasks
1.检查redo log_free_check();
2.做一次ibuf merge  
ibuf_contract_in_background(0, TRUE);
3.检查dict cache ,srv_master_evict_from_table_cache(100);
4.刷日志(srv_sync_log_buffer_in_background)
5.做一次新的checkpoint .log_checkpoint
idle 和 active的时候,所做的事情几乎是一样的,不同的是,在active状态下,每47秒才检查dict cache,每7秒才做一次check point 
因此在idle状态下,master线程可能会更加繁忙
B.在关闭实例时
调用srv_master_do_shutdown_tasks
1.log_free_check()
2.ibuf_contract_in_background(0, TRUE)
3.srv_sync_log_buffer_in_background()
4.log_checkpoint(TRUE, FALSE);

5.                srv_shutdown_print_master_pending(

                        last_print_time, n_tables_to_drop, n_bytes_merged);

原创文章,转载请注明: 转载自Simple Life

本文链接地址: [MySQL 5.6] Innodb后台线程之master线程

Post Footer automatically generated by wp-posturl plugin for wordpress.


Comments

Leave a Reply

Your email address will not be published. Name and email are required


Current month ye@r day *