共计 7280 个字符,预计需要花费 19 分钟才能阅读完成。
丸趣 TV 小编给大家分享一下 Innodb 检查点和 redo 写盘时机,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!
一、LSN
innodb 的 lsn 和 oracle 的 scn 一样,是一个重要的概念。是整个数据库数据同步的一种统一辨别标准,在很多地方都使用到了 LSN 比如
在 flush list 中正是是使用 page 的 oldest lsn 作为链表的条件
参考 buf_page_t 类中的 lsn_t oldest_modification; 变量
在 checkpoint 中记录的也是 lsn
参考宏 LOG_CHECKPOINT_LSN
在物理文件中每个 page 最后的刷新 lsn
参考宏 FIL_PAGE_LSN
在写日志落盘的时候也是以 lsn 为标准的
参考函数 log_write_up_to
实际上 lsn 就是表示的日志量的字节数,是一个累加的值,在 5.7 中表现为:
/* Type used for all log sequence number storage and arithmetics */ typedef ib_uint64_t lsn_t;
及一个 8 字节非负的整数。最大值及 2 的 64 次方。有了这种物理上概念,lsn 很容易换算为当前日志的偏移量。
二、innodb 中检查点的理解
这里我只讨论正常运行的情况下检查点。innodb 中类似 oracle 的增量检查点。正常运行 checkpoint 是由 master 线程触发。我们知道脏数据通过 page clean 线程和 lru manager 线程是在不断写盘的,那么在进行异常重启的的时候我们必须要知道一个恢复的起点,但是这个起点是不能记录在内存中必要固化到磁盘,恢复的时候读取这个点以后的 redo 进行恢复,而 checkpoint 就是完成这个事情下面是 checkpoint 的执行流程。
正常情况下 master 线程会每秒进行检查点其作用有(参考 log_checkpoint 函数):
检查是否有自上次检查点以来的脏数据写盘了。
如果有则在 redo 里面会为每个修改过的文件写入 MLOG_FILE_NAME, 完成后写入一个总 MLOG_CHECKPOINT(参考 fil_names_clear 函数)。
1、MLOG_FILE_NAME 主要记录至上次检查点以来更改过的数据文件。
2、MLOG_CHECKPOINT 主要记录检查点的 lsn。
这个步骤会遍历 fil_system- named_spaces 用于查找是否有自上次检查点以来修改过的文件链表。
如果有则在 redo log header 中写入相应的检查点信息包含(异步写)。
实际上我们可以理解检查点就是由 master 线程每秒醒来查看一下脏数据写到哪里了,然后将其记录到合适的位置,以备 carsh recovery 使用。(参考 srv_master_thread 函数)
三、show engine innodb 中的检查点信息
下面是一个没有任何更新操作的库的信息如下:
Log sequence number 697794162
Log flushed up to 697794162
Pages flushed up to 697794162
Last checkpoint at 697794153
Log sequence number:已经写到 log buffer 中的 lsn。
参考 mtr_t::Command::finish_write 函数。
Log flushed up to:已经写到日志文件的 redo 的 lsn。
参考 log_write_flush_to_disk_low 函数。
Pages flushed up to:此 lsn 之前的脏数据都已经写到了数据文件。
参考 log_buf_pool_get_oldest_modification 函数。
Last checkpoint at:最后一次检查点记录到了什么位置。
参考 next_checkpoint_lsn 函数。
下面是这段输出的源码:
fprintf(file, Log sequence number LSN_PF \n Log flushed up to LSN_PF \n Pages flushed up to LSN_PF \n Last checkpoint at LSN_PF \n ,
log_sys- lsn,
log_sys- flushed_to_disk_lsn,
log_buf_pool_get_oldest_modification(),
log_sys- last_checkpoint_lsn);
一般来讲 Log sequence number Log flushed up to Pages flushed up to Last checkpoint at,但是这里注意一下。Pages flushed up to 697794162 和 Last checkpoint at 697794153,显然这里是一个没有任何操作的库所以 Pages flushed up to 应该和 Last checkpoint at 相等,但是这里存在差值,差值为:
697794162-697794153 = 9
这刚好是 MLOG_CHECKPOINT 的长度源码片段如下:
oldest_lsn = log_sys- last_checkpoint_lsn + SIZE_OF_MLOG_CHECKPOINT /** Size of a MLOG_CHECKPOINT record in bytes.
The record consists of a MLOG_CHECKPOINT byte followed by
mach_write_to_8(checkpoint_lsn). */ #define SIZE_OF_MLOG_CHECKPOINT 9
四、我所 debug 的几种 redo 写盘的时机
master 线程每秒调用 栈帧(可能是 idle 可能是 active 和检测是否需要插入缓存合并有关)
#0 log_group_write_buf (group=0x33f29f8, buf=0x7fffa5b38000 \200\024 , len=512, pad_len=0, start_lsn=697764864, new_data_offset=166) at /root/mysql5.7.14/percona-server-5.7.14-7/storage/innobase/log/log0log.cc:1145 #1 0x0000000001a50f95 in log_write_up_to (lsn=697765068, flush_to_disk=true) at /root/mysql5.7.14/percona-server-5.7.14-7/storage/innobase/log/log0log.cc:1493 #2 0x0000000001a51163 in log_buffer_sync_in_background (flush=true) at /root/mysql5.7.14/percona-server-5.7.14-7/storage/innobase/log/log0log.cc:1553 #3 0x0000000001b84bd1 in srv_sync_log_buffer_in_background () at /root/mysql5.7.14/percona-server-5.7.14-7/storage/innobase/srv/srv0srv.cc:2312 #4 0x0000000001b85666 in srv_master_do_idle_tasks () at /root/mysql5.7.14/percona-server-5.7.14-7/storage/innobase/srv/srv0srv.cc:2586 #5 0x0000000001b85b6b in srv_master_thread (arg=0x0) at /root/mysql5.7.14/percona-server-5.7.14-7/storage/innobase/srv/srv0srv.cc:2744
master 线程每秒 checkpoint 调用 (可能是 idle 可能是 active 和检测是否需要插入缓存合并有关)
#0 log_group_write_buf (group=0x33f29f8, buf=0x7fffa5a38000 \200\024\002 , len=1024, pad_len=0, start_lsn=697789952, new_data_offset=139) at /root/mysql5.7.14/percona-server-5.7.14-7/storage/innobase/log/log0log.cc:1145 #1 0x0000000001a50f95 in log_write_up_to (lsn=697790725, flush_to_disk=true) at /root/mysql5.7.14/percona-server-5.7.14-7/storage/innobase/log/log0log.cc:1493 #2 0x0000000001a52247 in log_checkpoint (sync=true, write_always=false) at /root/mysql5.7.14/percona-server-5.7.14-7/storage/innobase/log/log0log.cc:1934 #3 0x0000000001b856f2 in srv_master_do_idle_tasks () at /root/mysql5.7.14/percona-server-5.7.14-7/storage/innobase/srv/srv0srv.cc:2596 #4 0x0000000001b85b6b in srv_master_thread (arg=0x0) at /root/mysql5.7.14/percona-server-5.7.14-7/storage/innobase/srv/srv0srv.cc:2744
page clean 线程调用 栈帧
#0 log_group_write_buf (group=0x33f29f8, buf=0x7fffa5a38000 \200\024\002 , len=13312, pad_len=1024, start_lsn=697778176, new_data_offset=468) at /root/mysql5.7.14/percona-server-5.7.14-7/storage/innobase/log/log0log.cc:1145 #1 0x0000000001a50f95 in log_write_up_to (lsn=697790015, flush_to_disk=true) at /root/mysql5.7.14/percona-server-5.7.14-7/storage/innobase/log/log0log.cc:1493 #2 0x0000000001c704c7 in buf_flush_write_block_low (bpage=0x7fffc0cae940, flush_type=BUF_FLUSH_LIST, sync=false) at /root/mysql5.7.14/percona-server-5.7.14-7/storage/innobase/buf/buf0flu.cc:1035 #3 0x0000000001c70cea in buf_flush_page (buf_pool=0x33247d8, bpage=0x7fffc0cae940, flush_type=BUF_FLUSH_LIST, sync=false) at /root/mysql5.7.14/percona-server-5.7.14-7/storage/innobase/buf/buf0flu.cc:1237 #4 0x0000000001c717f4 in buf_flush_try_neighbors (page_id=..., flush_type=BUF_FLUSH_LIST, n_flushed=0, n_to_flush=25) at /root/mysql5.7.14/percona-server-5.7.14-7/storage/innobase/buf/buf0flu.cc:1466
当前线程 commit 调用栈帧如下:
#0 log_group_write_buf (group=0x33f29f8, buf=0x7fffa5a38000 \200\024\002 , len=2560, pad_len=0, start_lsn=697762816, new_data_offset=230) at /root/mysql5.7.14/percona-server-5.7.14-7/storage/innobase/log/log0log.cc:1145 #1 0x0000000001a50f95 in log_write_up_to (lsn=697765030, flush_to_disk=true) at /root/mysql5.7.14/percona-server-5.7.14-7/storage/innobase/log/log0log.cc:1493 #2 0x0000000001a51087 in log_buffer_flush_to_disk (sync=true) at /root/mysql5.7.14/percona-server-5.7.14-7/storage/innobase/log/log0log.cc:1524 #3 0x00000000019a9157 in innobase_flush_logs (hton=0x2e9fdd0, binlog_group_flush=true) at /root/mysql5.7.14/percona-server-5.7.14-7/storage/innobase/handler/ha_innodb.cc:4407 #4 0x0000000000f65893 in flush_handlerton (thd=0x0, plugin=0x7ffff03588e8, arg=0x7ffff0358944) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/handler.cc:2606 #5 0x00000000015d7716 in plugin_foreach_with_mask (thd=0x0, func=0xf65835 flush_handlerton(THD*, plugin_ref, void*) , type=1, state_mask=4294967287, arg=0x7ffff0358944) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/sql_plugin.cc:2318 #6 0x0000000000f658ef in ha_flush_logs (db_type=0x0, binlog_group_flush=true) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/handler.cc:2617 #7 0x000000000185733d in MYSQL_BIN_LOG::process_flush_stage_queue (this=0x2e02c80, total_bytes_var=0x7ffff0358a88, rotate_var=0x7ffff0358a87, out_queue_var=0x7ffff0358a78) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/binlog.cc:8541 #8 0x000000000185899f in MYSQL_BIN_LOG::ordered_commit (this=0x2e02c80, thd=0x7fff2c000b70, all=false, skip_commit=false) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/binlog.cc:9189 #9 0x000000000185700c in MYSQL_BIN_LOG::commit (this=0x2e02c80, thd=0x7fff2c000b70, all=false) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/binlog.cc:8440 #10 0x0000000000f63df8 in ha_commit_trans (thd=0x7fff2c000b70, all=false, ignore_global_read_lock=false)
innodb shutdown(未 debug)
redo buffer 不足(未 debug)
以上是“Innodb 检查点和 redo 写盘时机”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注丸趣 TV 行业资讯频道!