
2024-12-25T02:25:10.558518+08:00 218983 [Warning] [MY-013360] [Server] Plugin mysql_native_password reported: ''mysql_native_password' is deprecated and will be removed in a future release. Please use caching_sha2_password instead'2024-12-25T02:25:11.987359+08:00 0 [Warning] [MY-012985] [InnoDB] A long semaphore wait:--Thread 140403799836416 has waited at dict0dict.cc line 2570 for 916 seconds the semaphore:Mutex at 0x7fb59ea91aa0, Mutex DICT_SYS created dict0dict.cc:1018, locked by 1404126700725762024-12-25T02:27:14.331095+08:00 0 [Warning] [MY-012985] [InnoDB] A long semaphore wait:--Thread 140395180500736 has waited at ha_innodb.cc line 7170 for 867 seconds the semaphore:Mutex at 0x7fb59ea91aa0, Mutex DICT_SYS created dict0dict.cc:1018, locked by 140412670072576

然后调取了一下主机的CPU和内存使用情况,很明显发现,内存的耗尽时间点和MySQL数据库服务重启的时间点是吻合的。

还发现三天前也出现同样的内存消耗趋势情况,虽然之前的时间没有反馈业务异常,但从内存使用情况看,也知道出现过数据库服务重启,也可以推断每三天出现一次。
主机总的内存有64G,给到innodb_buffer_pool_size也只有4G,查看整个数据库使用的内存,也只有10G左右。

从数据库的各种内存池使用情况来看,是绝对不对使用到那么多内存的,计算加起来也就13G不到。

再根据官方文档提供的,消耗内存的组件,计算加起来,也没有到达30G。

然而top查看,看到的是,mysqld服务进程消耗的内存比10G大好几倍。

那mysqld消耗的这么多主机内存,究竟去了哪里呢。查看官网,MySQL 8.0都没有找到相应的BUG,最后想到了业务应用连接数据库创建的会话,断开之后,可能占用的内存资源没有释放导致的,那就是glibc的内存管理器自身缺陷导致。
简言之,就是调用glibc申请的内存使用完毕后,归还给OS时没有被正常回收,而变成了碎片,随着碎片的不断增长,就能看到mysqld进程占用的内存不断上升。这时,可以调用函数主动回收释放这些碎片。
可以使用以下方法,可以对mysqld服务进程消耗的内存进行部分释放,不过要记得,这个操作尽量选择在业务少的时间段进行。
gdb --batch --pid `pidof mysqld` --ex 'call malloc_trim(0)'或者gdb -p <mysqld_pid>
max_connections = 500 --改小max_connect_errors = 100 --增大max_heap_table_size = 8M --改小innodb_log_buffer_size = 8M --改小innodb_buffer_pool_size = 8G --增大

自从修改了这部分参数之后,以上每3天出现一次重启的情况没有了,直到目前为止,也没有出现过内存耗尽的情况。虽然mysqld服务消耗的内存,依然还是比较大,但是经后期观察,内存增长到主机总内存的75%左右,就不会继续往上增长,继续消耗,还出现一个小部分内存的释放。看到这样,也终于是把mysqld大量消耗内存和重启的问题控制住了,解决掉了。

总结:
安装MySQL 8.0的时候,需要注意innodb_buffer_pool_size和max_connections两个参数的设置,需要根据主机的实际内存和业务需求,设置合理的范围,缓存池不宜过小,最大连接数不宜过大。
也可以安装jemalloc, 可以更好地管理内存碎片,从而降低内存使用峰值。在高并发环境下,jemalloc 的性能通常优于默认的 glibc 分配器。
附加:
gdb安装方法:
# yum -y install gcc wget texinfo# wget https://mirrors.tuna.tsinghua.edu.cn/gnu/gdb/gdb-8.1.tar.gz --no-check-certificate# tar -zxf gdb-8.1.tar.gz# cd gdb-8.1# mkdir builddir# cd builddir# ../configure# make && make install# gdb --version
收回内存命令:
gdb --batch --pid `pidof mysqld` --ex 'call malloc_trim(0)'




