加入收藏 | 设为首页 | 会员中心 | 我要投稿 济源站长网 (https://www.0391zz.cn/)- 数据工具、数据仓库、行业智能、CDN、运营!
当前位置: 首页 > 服务器 > 安全 > 正文

《MySQL运维内参》节选

发布时间:2021-01-15 02:42:04 所属栏目:安全 来源:网络整理
导读:《《MySQL运维内参》节
副标题[/!--empirenews.page--]

《《MySQL运维内参》节选》要点:
本文介绍了《MySQL运维内参》节选,希望对您有用。如果有疑问,可以联系我们。

引子:

书接上文,在之前六篇讲述了写日志,其实正常情况下,这都是无用功,因为根本用不到.上一节讲到了,在什么情况下会用到日志,以及在什么时候会用到,如何用到等等内容,我们这一节继续讲述,在扫描完成日志之后,如何做数据库恢复工作,里面有什么逻辑,有什么可以改进的地方等等,这都是我们读者要去深思的地方.

(本书作者在“白家大院”齐聚首)

从这些代码段中可以看到,缓存到HASH表之后,应该是可以找合适的时机去APPLY了,那什么时候呢?我们可以返回去看看函数recv_scan_log_recs的最后,调用了函数recv_apply_hashed_log_recs,那这个就是我们要找的真正做APPLY的函数了.我们详细看一下它的实现.

继续:

从这些代码段中可以看到,那这个就是我们要找的真正做APPLY的函数了.我们详细看一下它的实现.

UNIV_INTERN void recv_apply_hashed_log_recs(

? ? ibool ? allow_ibuf

)? ?

{

? ? /* local vaiables … */

loop:

? ? recv_sys->apply_log_recs = TRUE;

? ? recv_sys->apply_batch_on = TRUE;

? ? /* 遍历HASH表?是的,把HASH表中的每一个桶中的每一个页面,连续处理 */

? ? for (i = 0; i < hash_get_n_cells(recv_sys->addr_hash); i++) {

? ? ? ? /* 遍历HASH表一个桶中的多个地址 */

? ? ? ? for (recv_addr = static_cast<recv_addr_t*>(

? ? ? ? ? ? ? ? HASH_GET_FIRST(recv_sys->addr_hash,i));

?? ? ? ? ? ? recv_addr != 0;

?? ? ? ? ? ? recv_addr = static_cast<recv_addr_t*>(

? ? ? ? ? ? ? ? HASH_GET_NEXT(addr_hash,recv_addr))) {

? ? ? ? ? ? /* 针对每一个页面,做这个页面上所有的REDO操作 */

? ? ? ? ? ? ulint ? space = recv_addr->space;

? ? ? ? ? ? ulint ? zip_size = fil_space_get_zip_size(space);

? ? ? ? ? ? ulint ? page_no = recv_addr->page_no;

? ? ? ? ? ? if (recv_addr->state == RECV_NOT_PROCESSED) {

? ? ? ? ? ? ? ? mutex_exit(&(recv_sys->mutex));

? ? ? ? ? ? ? ? if (buf_page_peek(space,page_no)) {

? ? ? ? ? ? ? ? ? ? buf_block_t*? ? block;

? ? ? ? ? ? ? ? ? ? mtr_start(&mtr);

? ? ? ? ? ? ? ? ? ? block = buf_page_get(

? ? ? ? ? ? ? ? ? ? ? ? space,zip_size,page_no,

? ? ? ? ? ? ? ? ? ? ? ? RW_X_LATCH,&mtr);

? ? ? ? ? ? ? ? ? ? buf_block_dbg_add_level(

? ? ? ? ? ? ? ? ? ? ? ? block,SYNC_NO_ORDER_CHECK);

? ? ? ? ? ? ? ? ? ? /* 恢复一个页面的数据,APPLY recv_addr中存储的所有REDO记录,

? ? ? ? ? ? ? ? ? ? 这里使用了一个MTR来恢复.需要注意的是,这个MTR只是用来

? ? ? ? ? ? ? ? ? ? 获取页面时,给这个页面加锁使用的,而不会涉及REDO操作,因为

? ? ? ? ? ? ? ? ? ? REDO是不需要再写日志的,所以不用担心这个MTR涉及到的日志量

? ? ? ? ? ? ? ? ? ? 太大的问题 */

? ? ? ? ? ? ? ? ? ? recv_recover_page(FALSE,block);

? ? ? ? ? ? ? ? ? ? mtr_commit(&mtr);

? ? ? ? ? ? ? ? } else {

? ? ? ? ? ? ? ? ? ? /* 这里的操作是,如果上面的buf_page_peek没有在Buffer Pool中

? ? ? ? ? ? ? ? ? ? 找到这个页面,那这里就从文件中将这个页面载入到Buffer Pool,

? ? ? ? ? ? ? ? ? ? 并且预读32个页面以提高性能.恢复方法与是一样的.*/

? ? ? ? ? ? ? ? ? ? recv_read_in_area(space,page_no);

? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? mutex_enter(&(recv_sys->mutex));

? ? ? ? ? ? }

? ? ? ? }

? ? }

? ? /* Wait until all the pages have been processed */

? ? while (recv_sys->n_addrs != 0) {

? ? ? ? mutex_exit(&(recv_sys->mutex));

? ? ? ? os_thread_sleep(500000);

? ? ? ? mutex_enter(&(recv_sys->mutex));

? ? }

? ? /* Wait for any currently run batch to end.?

? ? 如注释所述,如果上面的操作做完了,则需要保证这些日志APPLY之后

? ? 要在ibdata及ibd(s)中落地,此时就会将Buffer Pool中全部的脏页刷一遍

? ? 以保证已经处理的这些日志失效.可能有人会问,如果在恢复的过程中,假设

? ? 就是这里吧,还没有做刷盘操作,数据库又挂了,那怎么办?

? ? 其实没事儿,整个恢复过程,日志也没有写,只是扫描了一遍,并且有可能在

? ? Buffer Pool中已经写了很多页面,有可能这些页面已经因为LRU已经刷过

? ? 了,但这些操作是可重入的,也就是说,数据库再起来,可以重新做一次REDO

? ? 操作,直到做成功为止.*/

? ? success = buf_flush_list(ULINT_MAX,LSN_MAX,NULL);

? ? recv_sys->apply_log_recs = FALSE;

? ? recv_sys->apply_batch_on = FALSE;

? ? /* 将HASH表中缓存的所有内容清空 */

? ? recv_sys_empty_hash();

? ? mutex_exit(&(recv_sys->mutex));

}

到这里,我们应该已经清楚了REDO数据库恢复的整个过程,并且可以返回到函数recv_recovery_from_checkpoint_start_func中,看一下最后的说明,做完REOD之后,做一次检查点以说明这次数据库恢复已经完成.

但这里我又有话说了,各位同学有没有发现一个细节,那就是InnoDB在辛辛苦苦的将所有日志分析并且根据不同页面通过HASH表存储之后,我们特别要注意下面两点特征:

  1. 对于同一个页面的REDO记录,必然是存储在同一个HASH桶中的.
  2. 对于某一个页面的所有日志记录,是按照先后顺序来管理的.

这两个特征非常重要,因为我们知道,REDO日志的APPLY,与顺序有关系,LSN小的,必定要比LSN大的先做APPLY,不然有可能造成数据的覆盖.但这有一个前提就是同一个页面,不同页面之间是不存在这样的问题的.

那我们想想,是不是只需要保证,同一个页面的日志顺序执行其所有的日志记录即可,而不同页面就没必要守这个规则了,答案是肯定的.

那目前InnoDB难道不是这样做的么?上面代码中我们已经看到了,他是用了一个两层循环,扫描了整个HASH表,慢慢的一条条的做REDO恢复.基于上面的分析,其实可以大胆的想象的一下,REDO恢复可以实现并行恢复.按照桶的下标为键值分配线程,那这样同一个桶必然会分到同一个线程中去做,这样自然保证了同一个页面的执行顺序,而不同的桶之间的页面是没有关系的,自然就可以并行恢复了.

啊?可以这样?这个想法,可能会让那些把日志文件设置的很大,又经常出现机器宕机问题的同学(上面已经提到了他们)心潮澎湃,这样性能提升的不只一点点了.

还是那句话,这个是需要把日志文件设置很大,并且经常出现宕机时,优化效果才明显.有需求,就能解决,我们希望这个优化会出现在某个版本中,少一些浪费的时间.

到现在为止,REDO日志的恢复就做完了,到这个时候,才真正体现了这个“累赘”的价值,感谢有你!

上面所讲的,是使用REDO日志来恢复数据库的过程,在它做完之后,整个数据库就是完整的了,已经保证了所有的数据库表都没有丢数据的情况,所有的数据库页面也已经是完整的了.假设此时对数据库做DML操作,也已经是可以的了,但还有一个问题没有处理,那就是此时的数据库,存在脏数据.因为有些事务没有提交,但数据已经存在了(举一个例子,事务在做的过程中,日志已经写完并刷盘,就是没有提交,此时数据库挂了),那根据事务的ACID特性,这样的数据就不应该存在,此时InnoDB需要做的就是把这些事务回滚掉,这就用到了我们下面将要讲的“数据库回滚”.

(神形兼备啊,另外那种霸气也流露出来了)

数据库回滚

(编辑:济源站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读