vc mysql init 崩溃_故障分析 | 崩溃恢复巨慢原因分析

作者:xuty

本文来源:原创投稿

*爱可生开源社区出品,原创内容未经授权不得随意使用,转载请联系小编并注明来源。

一、现象

有个 MySQL 5.7 开发库异常挂掉后,奔溃恢复一直处于如下位置,且持续了 2 小时左右才起来。非常疑惑这段时间 MySQL 到底做了什么事情?居然需要这么长时间。虽说这里虚拟机的 IOPS 并不是很高,但也绝对不需要这么久吧?而且从日志输出来看,这块应该也不是在做真正的数据恢复,那么也可以排除是大事务回滚导致的耗时长,那么原因到底是啥呢?

值得注意的是,这台开发库上面有将近 1500 个库和上万张表,难道MySQL 崩溃恢复时长和表的数量也存在一定关系嘛?

476197aedad1a84db6109402d76bcaff.png

二、分析栈帧

在 MySQL 崩溃恢复时,用pstack打了栈帧,再用pt-pmp工具分析栈帧后显示如下:

pread64(libpthread.so.0),os_file_io(os0file.cc:5435),os_file_pread(os0file.cc:5612),os_file_read_page(os0file.cc:5612),os_file_read_no_error_handling_func(os0file.cc:6069),pfs_os_file_read_no_error_handling_func(os0file.ic:341),Datafile::read_first_page(os0file.ic:341),Datafile::validate_first_page(fsp0file.cc:551),Datafile::validate_to_dd(fsp0file.cc:404),fil_ibd_open(fil0fil.cc:3969),dict_check_sys_tables(dict0load.cc:1465),dict_check_tablespaces_and_store_max_id(dict0load.cc:1525),innobase_start_or_create_for_mysql(srv0start.cc:2329),innobase_init(ha_innodb.cc:4048),ha_initialize_handlerton(handler.cc:838),plugin_initialize(sql_plugin.cc:1197),plugin_init(sql_plugin.cc:1538),init_server_components(mysqld.cc:4033),mysqld_main(mysqld.cc:4673),__libc_start_main(libc.so.6),_start根据函数名字,感觉像是在遍历校验每个表空间文件的有效性?,难道 MySQL 崩溃恢复时会额外进行校验操作?貌似和表数量扯上点关系了。

三、GDB 调试Server version: 5.7.26-log MySQL Community Server (GPL)

直接去分析源码感觉有点找不到切入点,因为不知道正常启动是不是也是这样的函数调用。为了知道正常启动与崩溃恢复的区别,先在本地的 MySQL 5.7.26 环境中用 GDB 调试 MySQL 启动过程,看下正常启动和崩溃恢复的函数调用有哪些区别,再针对性的去分析源码比较好。

-- 将之前的栈帧弄成了树状,便于分析>innobase_init| >innobase_start_or_create_for_mysql| | >dict_check_tablespaces_and_store_max_id| | | >dict_check_sys_tables| | | | >fil_ibd_open| | | | | >Datafile::validate_to_dd| | | | | | >Datafile::validate_first_page| | | | | | | >Datafile::read_first_page| | | | | | | | >pfs_os_file_read_no_error_handling_func| | | | | | | | | >os_file_read_no_error_handling_func| | | | | | | | | | >os_file_read_page| | | | | | | | | | | >os_file_pread| | | | | | | | | | | | >os_file_io

正常启动 GDB 调试结果:

从上到下,每次打一个断点函数,发现到Datafile::validate_to_dd这个函数时,MySQL 正常启动就不会执行,看样子是fil_ibd_open函数中做了某些判断。

崩溃恢复 GDB 调试结果:

一边用 sysbench 压,一边直接 kill -9 进程就可以模拟崩溃恢复,同样从上到下,依次打断点函数,发现会走到Datafile::validate_to_dd这个函数中,Continue 后会一直断点在这个函数上,说明外层包装了一层循环会遍历所有表,如果继续增加断点函数的话,发现绝大部分表会继续走下去,直到os_file_io,而小部分表则不会继续走下去。

四、源码分析

4.1. fil_ibd_open

我们先去fil_ibd_open函数中看下,进入Datafile::validate_to_dd函数的判断条件,发现主要和一个validate参数有关,如果为false则可以跳过检测,为true则需要进入Datafile::validate_to_dd函数。

6efda04ba408aeac9bae7efef07d1ed9.png

4.2. innobase_start_or_create_for_mysql

然后我们需要看下validate参数的定义,分析崩溃恢复与正常启动的区别。发现validate 参数最早是在innobase_start_or_create_for_mysql函数中定义的,并且其注释已经解释的非常详细。1. 正常启动:直接为每张表的创建 space object 即可,不需要打开 ibd 文件的 header page 进行表空间校验。2. 崩溃恢复:为了数据字典的一致性,需要遍历打开所有 ibd 文件的 header page 进行表空间校验。

validate 这个参数表明当一个表空间被打开时,同时会去读取其 ibd 文件的头页(header page)来验证数据字典的一致性,而当数据库包含许多 ibd 文件时,这个过程就会比较久,所以只在崩溃恢复且非强制恢复时执行表空间校验操作!

83499c010be0e8bfc3bae8b91604a2ed.png

4.3. recv_needed_recovery & srv_force_recovery

接着我们来看下决定 validate 值的 2 个参数:recv_needed_recovery与srv_force_recovery,默认崩溃恢复时,recv_needed_recovery = 1 而 srv_force_recovery = 0 ,所以 validate = true,即需要进行表空间校验。

bool validate = recv_needed_recovery && srv_force_recovery == 0;//跳过表空间校验validate = false//执行表空间校验validate = true先看下recv_needed_recovery参数,默认为 0。MySQL 在启动时会比对checkpoint_lsn与flush_lsn。如果不相等,就会调用recv_init_crash_recovery方法将recv_needed_recovery置为。只有当 MySQL 正常关闭时,这 2 个 lsn 才会相等。另外一个小发现,MySQL 5.7 中服务起来后,什么操作都不做,checkpoint_lsn 永远会落后 9,所以即使你什么都不做,直接 kill -9 进程,也算是崩溃重启。

LOG---Log sequence number 2563079308Log flushed up to 2563079308Pages flushed up to 2563079308Last checkpoint at 2563079299

bb5d5dd8483a8e709043c9f90b882071.png

再来看下srv_force_recovery参数,默认值为 0,如果设置了 innodb_force_recovery ,那么 srv_force_recovery 的值就等于 innodb_force_recovery 的值,即只要配置了强制恢复,srv_force_recovery 就会大于 0。

4.4. dict_check_tablespaces_and_store_max_id

最后看下dict_check_tablespaces_and_store_max_id函数,根据注释介绍,这个函数会检查所有在数据字典中发现的表空间, 先检查每个共享表空间,然后检查每个独立表空间。

在崩溃恢复中,部分表空间已经在处理 redolog 时被打开(对应之前 GDB 调试时部分表未继续走下去),而其他没有被打开的表空间,将会通过比较数据字典中的 space_id 与表空间文件是否一致的方式进行验证(也就是之前所说的表空间校验过程)。

fd972f10b183db7bf1f11d80036c512d.png

五、测试验证

到这里,原理大概已经知道了,主要就是:MySQL 在崩溃恢复时,会遍历打开所有 ibd 文件的 header page 验证数据字典的准确性,如果 MySQL 中包含了大量表,这个校验过程就会比较耗时。那么我们可以模拟下这个场景,进一步验证,比如在测试库中用 sysbench 建 50W 张空表,然后模拟非正常关闭,对比下崩溃恢复时长。

06b871b9044ea0ab4b7d56d1af4b1008.png

可以看到 MySQL 下崩溃恢复确实和表数量有关,表总数越大,崩溃恢复时间越长。另外磁盘 IOPS 也会影响崩溃恢复时间,像这里开发库的 HDD IOPS 较低,因此面对大量的表空间,校验速度就非常缓慢。另外一个发现,MySQL 8 下正常启用时居然也会进行表空间校验,而故障恢复时则会额外再进行一次表空间校验,等于校验了 2 遍。不过 MySQL 8.0 里多了一个特性,即表数量超过 5W 时,会启用多线程扫描,加快表空间校验过程。

fbb1b695acc3f2faba36b5bf1d9b3a5e.png

MySQL 8.0.21 开始可以通过innodb_validate_tablespace_paths参数关闭正常启动时的表空间校验过程。

4da9a97943f54bbe633d5390d4bbb197.png

六、如何跳过校验

MySQL 5.7 下有方法可以跳过崩溃恢复时的表空间校验过程嘛?查阅了资料,方法主要有两种:1. 配置 innodb_force_recovery可以使 srv_force_recovery != 0 ,那么 validate = false,即可以跳过表空间校验。实际测试的时候设置 innodb_force_recovery =1,也就是强制恢复跳过坏页,就可以跳过校验,然后重启就是正常启动了。通过这种临时方式可以避免崩溃恢复后非常耗时的表空间校验过程,快速启动 MySQL,个人目前暂时未发现有什么隐患。2. 使用共享表空间替代独立表空间这样就不需要打开 N 个 ibd 文件了,只需要打开一个 ibdata 文件即可,大大节省了校验时间。自从听了姜老师讲过使用共享表空间替代独立表空间解决 drop 大表时性能抖动的原理后,感觉共享表空间在很多业务环境下,反而更有优势。

bool validate = recv_needed_recovery && srv_force_recovery == 0;

//跳过表空间校验

validate = false

//执行表空间校验

validate = true

临时冒出另外一种解决想法,即用 GDB 调试崩溃恢复,通过临时修改 validate 变量值让 MySQL 跳过表空间验证过程,然后让 MySQL 正常关闭,重新启动就可以正常启动了。但是实际测试发现,如果以 debug 模式运行,确实可以临时修改 validate 变量,跳过表空间验证过程,但是 debug 模式下代码运行效率大打折扣,反而耗时更长。而以非 debug 模式运行,则无法修改 validate 变量,想法破灭。

b9e24476f7e79f429cdb012a492d29fe.png

c9777a222b3283e275afa5b8e46172a2.png

附录:

https://dev.mysql.com/worklog/task/?id=7142

http://blog.symedia.pl/2015/11/mysql-56-and-57-crash-recovery.html

https://www.percona.com/community-blog/2019/07/23/impact-of-innodb_file_per_table-option-on-crash-recovery-time/

https://jira.mariadb.org/browse/MDEV-18733

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/396528.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

surfaceview结束后怎么处理_污泥压滤机处理后的污泥怎么处置

在污泥处理处置中,污泥压滤机处理污泥只是对污泥进行脱水,并没有实现污泥资源化处置。再进行污泥“减量化、无害化、资源化”处理时,许多企业用污泥压滤机对污泥脱水处理后就不知道怎么继续处置了,从而使污泥饼无处可去&#xff0…

js数组详解

1,什么是数组数组是值得有序集合,每个值叫做一个元素,而每个元素在数组中有一个位置,以数字表示,称为索引。js的数组是无类型的,数组元素可以是任意类型,同一个数组中的不同元素可能是对象或数组…

[转载]linux内存映射mmap原理分析

转自:http://blog.csdn.net/yusiguyuan/article/details/23388771 内存映射,简而言之就是将用户空间的一段内存区域映射到内核空间,映射成功后,用户对这段内存区域的修改可以直接反映到内核空间,同样,内核空…

判断一个指针有没有free_Free Code Camp的每个人现在都有一个档案袋

判断一个指针有没有freeby freeCodeCamp通过freeCodeCamp Free Code Camp的每个人现在都有一个档案袋 (Everyone at Free Code Camp now has a Portfolio) Note: we originally published this on our now-defunct blog in January of 2015.注意:我们最初是在2015年…

冒泡、快速排序小结

1.冒泡排序 (1) 比较领近的两个数 (2) 如果左边的比右边的数字大,则交换位置 (3) 向右移动一位,继续比较相邻的两个数 排序示例: 一轮排序结束后,最大值的位置已经移动最右端,再次如此循环,最终经过n-1次则…

python中until函数_等待应用程序窗口:python中的pywinauto.timings.WaitUntilPasses

我试图在pywinauto中使用waituntilpasses来给应用程序时间打开一个新窗口.我已使用SWAPY识别窗口详细信息.为了进行测试,我手动打开了子窗口,因此WaitUntilPasses应该立即看到该窗口,但是没有看到.语法显示为OK,因为我可以找到并打印find_windows的输出,如下所示:xx…

synchronized 异常_由浅入深,Java 并发编程中的 Synchronized

synchronized 作用synchronized 关键字是 Java 并发编程中线程同步的常用手段之一。1.1 作用:确保线程互斥的访问同步代,锁自动释放,多个线程操作同个代码块或函数必须排队获得锁,保证共享变量的修改能够及时可见,获得…

mysql正则通配符全解_mysql正则表达式与通配符

扩展正则表达式的一些字符是: “.”匹配任何单个的字符。 一个字符类“[...]”匹配在方括号内的任何字符。例如,“[abc]”匹配“a”、“b”或“c”。为了命名字符的一个范围,使用一个“-”。“[a-z]”匹配任何小写字母,而“[0-9…

dos常用文件操作命令

1、DIR 含义: 显示指定目录下的文件和子目录列表 类型: 内部命令 格式: DIR[drive:][path][filename][/p][/w][/A[[:]attributes]][/O[[:]sortorder]][/S][/B][/L] 举例: DIR DIR D:\px2 DIR D:\px2\*.txt DIR /A:D /O:D 2、COPY…

使您的Java代码闻起来很新鲜

by Marco Massenzio由Marco Massenzio 使您的Java代码闻起来很新鲜 (Make your Java code smell nice and fresh) A few years ago I joined a startup working on a cloud enterprise service that was originally built by an offshore team.几年前,我加入了一家…

MySQL时间戳与日期格式的相互转换

MySQL时间戳与日期格式的相互转换,PHP时间戳与日期格式的相互转换 MySQL: 获取当前时间SELECT NOW(); // 2018/10/11 14:22:51 时间日期格式转换成时间戳格式,UNIX_TIMESTAMP()SELECT UNIX_TIMESTAMP(NOW()); // 1539238930 时间戳格式转换成时间日期格式…

Linux内存分配机制之伙伴系统和SLAB

转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/6539590.html 内核内存管理的一项重要工作就是如何在频繁申请释放内存的情况下,避免碎片的产生。这就要求内核采取灵活而恰当的内存分配策略。通常,内存分配一般有两种情况&#xff1a…

this.$modal.confirm 自定义按钮关闭_自定义函数,让你玩转Excel得心应手

让“自动更正”输入统一的文本,你是不是经常为输入某些固定的文本,如《电脑报》而烦恼呢?那就往下看吧。1.执行“工具→自动更正”命令,打开“自动更正”对话框。2.在“替换”下面的方框中输入“pcw”(也可以是其他字符,“pcw”用小写),在“替换为”下面的方框中输…

php mysql 排名算法_MySQL PHP:优化排名查询和计数子查询

这是原始数据,并希望根据得分(count(tbl_1.id))对它们进行排名.[tbl_1]id | name1 | peter2 | jane1 | peter2 | jane3 | harry3 | harry3 | harry3 | harry4 | ron因此,制作临时表(tbl_2)来计算每个id的分数.SELECT id, name, COUNT( id ) AS scoreFROM tbl_1GROUP BY idORDER…

CCF-CSP 最大的矩形

问题描述在横轴上放了n个相邻的矩形,每个矩形的宽度是1,而第i(1 ≤ i ≤ n)个矩形的高度是hi。这n个矩形构成了一个直方图。例如,下图中六个矩形的高度就分别是3, 1, 6, 5, 2, 3。请找出能放在给定直方图里面积最大的矩…

Stack Overflow 2016年对50,000名开发人员进行的调查得出的见解

Today, Stack Overflow released the results of their 2016 survey of more than 50,000 developers.今天,Stack Overflow发布了他们2016年对50,000多名开发人员进行的调查的结果。 I’ve combed through this big document to bring you the most surprising ins…

web管理

1.站点根目录下查找是否被放置webshell***根据语句判断是不是PHP***脚本# find /storage/www/ -name "*.php" | xargs grep-in --color "eval("# grep -i --include*.php -r system\s*\( /storage/www/2.统计访问日志中来自同ip出现的次数分析盗链、***、机…

MySQL的主从复制云栖社区_MySQL-主从复制

前言前篇说了作为运维在数据库块最起码要会两大技能,今天来说说第二技能--主从复制随着业务的增长,一台数据库服务器以满足不了需求了,负载过重,这时候就需要减压,实现负载均衡读写分离,一主一从或一主多从…

数据存储(SharedPreferences存储)

SharedPreferences是通过 键值对 的方式存储数据SharedPreferences是通过键值对的方式存储的 将数据存储到SharedPreferences中有3种方法:1.Context类中的getSharedPreferences()方法2.Activity类中的getPreferences()方法3.PreferencesManager类中的getDefaultShar…

编程程序的名称要记住吗_学习编程时要记住的5件事

编程程序的名称要记住吗by Kurt由库尔特 学习编程时要记住的5件事 (5 Things to Remember When You’re Learning to Program) Learning to program is challenging. Aside from choosing a language or setting up a development environment that you know nothing about, t…