mysqld:表mysql.plugin不存在_TenDB Coredump优化: 不Dump Buffer Pool

        背景介绍        

MySQL实例在宕机时,会产生Core File。它保存了宕机时的现场,以便于后期的故障排查。在以前mysqld在写core file时,会将buffer pool的内容也一并dump出去,常常会写造成core file时间长,占用大量磁盘等问题。根据MySQL 8.0的新特性,TenDB引入了Core Dump时忽略Buffer Pool内容的功能。并发现此功能在MySQL 8.0中存在的两个Bugs。

     什么是Core File?    

Core File/Core Dump是记录一个进程的内存信息的镜像,包括一些寄存器信息,进程状态等。程序挂掉以后,可以根据Core File的信息做debug。

   为什么要忽略Buffer Pool?   

实际使用时,为了减少刷盘频率,通常会设置一个很大的Buffer Pool值。在Core Dump时就会产生一个很大的Core File,这样的话可能会带来三个问题。
1. 可能磁盘空间不够造成新的问题
2. 可能需要很长的时间写core file
3. 可能会有信息泄露的危险,毕竟Buffer Pool里面存放数据和索引。

     新功能速览    

新加了global参数

@@innodb_buffer_pool_in_core_file

ON表示记录buffer pool信息到core file中,OFF表示不记录,默认为ON。用户可以选择是否将buffer_pool dump到core file中。
如果需要不dump buffer pool,需要同时满足下面三个条件。
1. @@innodb_buffer_pool_in_core_fileOFF
2. @@core_fileON
3. 操作系统需要支持系统调用madvise(ptr,size,MADV_DONTDUMP)。这个调用可以使得在产生Core Dump时忽略某些信息,Linux Kernel 3.4以上的版本可以支持。

     测试记录    

目前的配置如下表

Variable_nameValueValue Explain
innodb_buffer_pool_size21474836482G
innodb_buffer_pool_instances8

8个

innodb_buffer_pool_chunk_size134217728128M

不忽略Buffer Pool时:

1. 启动mysqld;

./bin/mysqld --datadir=$datadir \--innodb-buffer-pool-in-core-file \--core-file --user=mysql &

2. 模拟杀死mysqld,让它产生core file;

kill -s SIGABRT $mysql_pid

3. 在data目录中看core file的大小,这里是2.8G。

ab16459754db55819ac788b6ae715b5e.png

忽略Buffer Pool时:

1. 启动mysqld;

./bin/mysqld --datadir=$datadir \--skip-innodb-buffer-pool-in-core-file \--core-file --user=mysql &

2. 模拟杀死mysqld,让它产生Core File;

kill -s SIGABRT $mysql_pid

3. 同样的配置,看一下结果,只有652M了。

32fcedfaf45ad93f8958f0615e13bb55.png

        实现原理        

实现参照了MySQL 8.0中由Facebook提交的一个patch,并对TenDB做了适配和优化。

原来buffer_pool在分配/释放大片内存时,会用到以下的两个函数。

pointer allocate_large(...);void deallocate_large(...);

现在需要做的功能是,通过一些参数判断,决定core dump时,是否需要dump出这些内存。

于是在初始化buffer control block时添加了

static bool buf_pool_should_madvise = false;

这个参数用于表示当前的参数是否需要把buffer pool dump到core file中,对这个参数的改变是需要通过新加的互斥锁chunk_mutex保护的。这样可以防止

1. 初始化时chunk时,@@innodb_buffer_pool_in_core_file改变 (这种情况很少)
2. 运行时,@@innodb_buffer_pool_size改变

对每个chunk,实现了以下两个函数,最后落地是否dump

/* 主要是通过调用 madvise(mem, mem_size(), MADV_DODUMP) */bool buf_chunk_t::madvise_dump(); /* 主要是通过调用 madvise(mem, mem_size(), MADV_DONTDUMP) */bool buf_chunk_t::madvise_dont_dump();

因为新加了状态buf_pool_should_madvise,原来的分配方式是没有should_dump状态的,所以新增了两个分配/释放函数,在其中包装了原来的分配功能。(相当于一个wrapper)

// 其中实现了allocator.allocate_large()// 并维护buf_pool_should_madvise状态bool buf_pool_t::allocate_chunk(...)// 其中实现了deallocator.allocate_large()// 并维护buf_pool_should_madvise状态void buf_pool_t::deallocate_chunk(...);

为了解决运行时更新参数@@innodb_buffer_pool_in_core_file的问题,写了以下函数来更新buf_pool_should_madvise的状态,注意,这里必须对所有chunk加互斥锁实现。

void buf_pool_update_madvise();

最后在调用方面,实现了两个函数,对所有的chunks进行遍历,进行dump/dontdump,这里不进行详述。

        Bug说明       

在测试过程中,发现Facebook提交的这些代码有两个Bug。

Bug1: mysql-test找不到core file (Fixed)

在MySQL 8.0提供的mysql-test中,会出现找不到core file的问题

e60fdc265d812441b0dd0d9b46d24593.png

     Bug出现的原因    

MySQL 8.0是通过在mysql-test的data目录下寻找core file的,通常这个目录是mysql-test/var/mysqld.1/data/。而实际上,core file不一定在这个目录中。

/proc/sys/kernel/core_pattern这个文件的内容决定了core file的路径和命名方式。

cat /proc/sys/kernel/core_pattern

如果结果是core,那么表示是一个相对路径,命名方式为core.$pid

而路径也可以不是一个在data下的路径,比如某机器机上为/data/corefile/core_%e_%t,这个表示core file产生的位置是/data/corefile,命名方式为core_$进程名_$dump时间.$pid,例如core_mysq-test_1577090676.28888。

所以,原mysql-test的寻找策略是有问题的。

        解决方案       

在TenDB中,我们通过修改mysql-test寻找core file的策略,分析系统的core_pattern,在系统指定的路径下,寻找core file。从而可以解决非data目录下的core file无法找到的问题。

Bug2: 无法判断内核是否支持MADV_DONTDUMP

可以知道,整个功能最依赖的就是madvise()这个函数,以及它支不支持MADV_DONTDUMP。

Facebook的做法是,通过在configure.cmake中加入了以下的语句

include(CheckSymbolExists)CHECK_SYMBOL_EXISTS(MADV_DONTDUMP "sys/mman.h" HAVE_MADV_DONTDUMP)# 下面代码用于测试输出IF (HAVE_MADV_DONTDUMP)MESSAGE(STATUS, "Platform supports MADV_DONTDUMP")ELSE()MESSAGE(FATAL_ERROR, "Platform does not support MADV_DONTDUMP")ENDIF()

根据 Linux Manual所述“MADV_DONTDUMP (since Linux 3.4)”,即这个参数是 Linux 3.4 之后才有的。
但是实际测试时,发现在Linux 2.6的机器中也输出了Platform supports MADV_DONTDUMP

     Bug出现的原因    

其实

CHECK_SYMBOL_EXISTS(MADV_DONTDUMP "sys/mman.h" HAVE_MADV_DONTDUMP)

只是check 的glibc-headers的头文件,并不是系统内核的头文件。可以用rpm -ql glibc-headers查看glibc headers文件列表。
结果发现在一个glibc的头文件中有对这个宏的定义

#define MADV_DONTDUMP 16

而glibc是编译时的行为,不能实际反映kernel是否支MADV_DONTDUMP

这个Bug会在以下两个情况中发生

1. 在高版本的Linux机器编译,低版本机器中运行;

2. 机器的glibc处于较高版本,而机器内核版本较低。

     如何解决这个Bug    

在Linux内核中,检测参数是否存在的函数是madvise_behavior_valid();可惜这个函数是static的,意味着外部无法调用。

于是,如果想要解决这个问题,只能够在运行时测试一组合法数据的dump/dontdump,看结果是否出错,来确定系统是否支持这两个参数。但是由于madvise可能出错的原因很多,并且这个解决方案并不优雅,所以暂时没有采用这样的解决方案。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值