告别内存OOM,解决MySQL内存增长问题
本文分享自华为云社区《【华为云MySQL技术专栏】MySQL内存增长问题分析案例》,作者:GaussDB 数据库。
前言
在现网环境中,偶尔会遇到客户实例内存OOM(Out Of Memory,即内存耗尽或溢出)的情况。MySQL数据库作为一款面向高并发应用场景的系统软件,因其应用场景复杂且函数调用链极长,导致分析内存异常问题变得非常困难。
MySQL提供了Performance Schema功能,用于跟踪其性能指标,包括内存占用情况。但该工具是有一定的局限性,只能监控通过MySQL提供的内存分配接口分配的内存,不能监控直接使用malloc或者new函数分配的内存。这种情况我们就可以借助jeprof工具(jeprof是jemalloc配套的内存分析工具)来定位,以下是借助jeprof定位MySQL内存问题的分析过程。
问题描述
在生产环境中,某客户的实例频繁出现OOM,通过排查客户业务,发现是大事务导致的内存异常增长,该实例的MySQL版本为8.0.22(MySQL 8.0.25以后的版本解决了内存异常增长问题),我们通过如下方式在本地进行复现:
1. 采用sysbench往一张表中压入100000000条数据,如下:
sysbench --mysql-host=xxx --mysql-port=xxx --mysql-user=xxx --mysql-password=xxx \/usr/share/sysbench/oltp_read_write.lua --tables=1 \--table_size=100000000 prepare
begin; update sbtest1 set k=k+1;
该语句执行前,通过top命令查看到的内存使用情况如下:
语句执行过程中,内存持续增长,执行完毕时,其内存占用如下:
执行过程中,物理内存增长了近2.6g,显然占用异常,若并发量较大的情况下,势必会OOM。
定位过程
1. 查看performance_schema相关的内存监控数据
遇到MySQL的内存问题,首先想到的是打开performance_schema开启MySQL自带的内存监控,这些监控在相当一部分场景下的确发挥了重要作用。
例如,可以使用如下的命令查看内存情况:
select event_name, current_alloc from sys.memory_global_by_current_bytes limit 20;
但performance_schema监控数据也有一些局限性。比如当前的这个场景,MySQL自带的内存监控并没有采样到任何的内存变化。这是因为自带的内存监控只能监控到通过MySQL内存分配函数分配的内存,比如以mem_block_info_t为单位的MySQL内存分配函数等。所以,直接通过malloc或者new分配的函数,自带内存监控是无法监控到的。
jeprof可以捕获所有的malloc和free函数的调用,不过由于glibc默认的分配器是ptmalloc,因此,需要一些配置将默认的ptmalloc替换成jemalloc。
下载jemalloc源码,启用--enable-prof,编译出对应的libjemalloc.so.2,jeprof工具即可,具体如下:
步骤一:下载jemalloc源码,进入解压后的目录,执行如下命令编译出对应的libjemalloc.so.2,jeprof工具;
cd {jemalloc解压后的目录} ./autogen.sh --enable-prof ./configure --enable-prof
export MALLOC_CONF="background_thread:true,narenas:4,dirty_decay_ms:5000,prof:true,prof_prefix:/opt/workdir/logs/log,lg_prof_interval:30,lg_prof_sample:19"
export LD_PRELOAD='/jemalloc/libjemalloc.so.2' // 步骤一编译出来的libjemalloc.so.2路径
结果分析
关于jeprof结果解析的命令,这里不再赘述,具体可以通过jeprof -h查看。
就本文的问题而言,实际上只需要关心从语句执行开始到语句执行结束内存的变化部分就可。那么,就可以通过如下命令对比第一次生成的profing数据以及最后一次的profling数据:
/jemalloc/jeprof --pdf ./mysqld --base=log.start.heap log.end.heap > ../xxx.pdf
这里取部分结果的截图做分析:
void Rpl_transaction_write_set_ctx::add_write_set(uint64 hash) { DBUG_TRACE; DBUG_EXECUTE_IF("add_write_set_crash_no_memory", throw std::bad_alloc();); write_set.push_back(hash); }
参考《STL源码剖析》一书, vector的底层数据结构其实就是一段连续的线性空间,以start指针和fininsh指针分别指向已申请的连续空间中目前已被使用的范围,以end_of_storage指针指向连续空间的尾端,当原空间使用完,也即fininsh==end_of_storage时,vector会执行的动态扩容,也就是_M_realloc_insert过程, 其步骤如下:
而write_set恰是一个vector, 因此可以确定write_set占用了3072M内存从而导致内存的异常增长。这其实也是vector错误使用的一个典型案例,对于这种大量的push_back场景,由于vector的2倍扩容,不仅会导致内存占用过多,扩容的过程中反复的申请新内存、释放旧内存也会导致性能问题。若仅考虑当前的问题场景,显然list是更优的选择。
注意事项
1. 编译jemalloc时,注意./autogen.sh --enable-prof 以及./configure --enable-prof 都需要加上--enable-prof选项,若仅在./autogen.sh是加上--enable-prof参数,这种情况下你需要在启动的时候以如下方式启动mysqld, 否则无法生成profiling文件:
LD_PRELOAD='/jemalloc/libjemalloc.so.2' bin/mysqld &
2. 注意MALLOC_CONF的参数中lg_prof_interval参数。该参数设置过小,会严重影响mysqld的性能。当执行性能下降后,某些场景可能就不会复现。比如本文所涉及的问题场景,lg_prof_interval设置的过小,就几乎观察不到明显的内存变化。
3. 通过jeprof采样到的数据没有捕获到buffer pool的内存分配,这是因为jeprof是通过在jemalloc中设置采样点来采集数据的,只有应用程序通过malloc, free分配释放内存才会被采集到,而MySQL的buffer pool内存是直接通过mmap系统调用分配的,不经过jemalloc, 可以参考MySQL的large_page_aligned_alloc函数,所有的大内存均是通过该函数分配的。
inline void *large_page_aligned_alloc(size_t n_bytes) { int mmap_flags = MAP_PRIVATE * MAP_ANON; void *ptr = mmap(nullptr, n_bytes, PROT_READ * PROT_WRITE, mmap_flags, -1, 0); return (ptr != (void *)-1) ? ptr : nullptr; }
总结
上述客户业务中出现的问题,归根结底是代码中未对vector的内存进行限制,才有了大事务场景下内存无限增长最终导致OOM发生。华为云RDS for MySQL和GaussDB(for MySQL)完全兼容MySQL,华为云数据库在产品中对该问题进行了提前修复,后来开源MySQL在高版本中也对该问题也进行了修复。因此,MySQL内存问题可以结合MySQL提供的performance schema内存表和jeprof工具来辅助定位。

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
星创编辑器在投放业务中的落地|得物技术
搭建一个落地页需要涉及到多方合作,需要不断地进行沟通协调。繁杂的流程需要耗费很多的时间,因此我们推动产品重新搭建了一个专门服务于软广投放流程的编辑器——星创,完成广告搭建在投放业务各系统中的闭环。 一、落地页技术架构 名词解释 模板:就是投放业务人员配置一个完整的落地页。 站外落地页:投放在媒体,站外的用户看到的落地页。 站内落地页:用户点击站外落地页,进入App站内看到的H5页面。 编辑器:是一个提供投放业务人员的搭建平台。由(画布+设置器)+生成器组成,搭建的数据源是运营常用落地页模板,模板的组成又分为基础模板、玩法模板、定制化模板,实体间遵循的通信协议是DSL。 技术架构图 落地页的大体功能可以参考下面整体的架构图。 整体的架构包含应用层、B端编辑器SDK、C端Node渲染层、以及基于nest.js数据服务存储层。 下面我将从基础框架、模版类型配置、模版渲染3个方面阐述落地页编辑器的技术选型思路。 基础框架搭建 我们是基于pnpm+monorepo+turbo重新搭建的一个新项目。因为我们涉及到3个端的应用,有SSR、nest.js后端服务、前端H5 editor编辑器应用。整...
- 下一篇
一周万星的文本转语音开源项目「GitHub 热点速览」
上周的热门开源项目让我想起了「图灵测试」,测试者在不知道对面是机器还是人类的前提下随意提问,最后根据对方回复的内容,判断与他们交谈的是人还是计算机。如果无法分辨出回答者是机器还是人类,则说明机器已通过测试,具有人类的智力水平。 虽然现在大模型的回答还充满 AI "味",可以一眼识破,但 GitHub 上有个开源项目:ChatTTS,它根据文本生成的语音,已经可以做到"以假乱真",不单单是我这么觉得,一周飙升了 1w+ Star,已经足以说明大家对它的认可。 作者为了限制 ChatTTS 生成的语音,在 4 万小时模型的训练过程中添加了少量额外的高频噪音,并尽可能压缩了音质,让其更好分辨出来,从而防止不法分子用它进行诈骗等违法行为,看来生成效果已经好到作者自己都"害怕"的地步了?* 还有位开发者(lihaoyun6)因为看不惯 macOS 的录屏软件收费,就自己动手做了一个轻巧的 macOS 屏幕录制工具:QuickRecorder,它不仅功能齐全还免费开源。如果你觉得自己桌面有点单调,这有个小工具(RunCat_for_windows)可以在任务栏上显示一只奔跑的小猫,它会陪着你一起加...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7
- CentOS关闭SELinux安全模块
- SpringBoot2更换Tomcat为Jetty,小型站点的福音
- CentOS6,CentOS7官方镜像安装Oracle11G
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
- Red5直播服务器,属于Java语言的直播服务器
- CentOS7编译安装Cmake3.16.3,解决mysql等软件编译问题
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作
- SpringBoot2整合Thymeleaf,官方推荐html解决方案
- CentOS8安装Docker,最新的服务器搭配容器使用