>>环境信息:
操作系统版本: CTyunOS release 2 22.06.1
内核版本: 4.19.90-2102.2.0.0064.ctl2.x86_64
数据库初始版本: 5.7.39, for Linux (x86_64)
>>问题梳理
1,2022.11 创建安装实例
3台物理机64C768G,8set1主2从
部署完成后,业务未上线,监控无异常
1,2024.02 参照《MySQL加载Jemalloc库的排查手段及说明(含arm版)》修复jemalloc
修复后,频繁出现Out of memory导致的实例重启(空闲内存充足)
2,关闭numa,协调主机排查其他软硬件
问题依旧
3,2022.06.25 关闭jemalloc
堆栈信息大量内存和libjemalloc相关信息,测试关闭jemalloc
OOM重启不再出现,mysqld进程内存泄漏且free较大情况下swap耗尽
4,2024208.09 尝试升级至5.7.46(默认开启jemalloc)
仍然频繁出现Out of memory导致的实例重启
5,2022.08.10 调整jemalloc配置为系统库文件
无效,仍然频繁出现Out of memory导致的实例重启
6,2022.08.11 尝试升级最新版本至5.7.49
暂无异常,继续观察
系统频繁重启,目前已经替换最新的包,担心再次oom及排查之前oom的原因,今天上午10点找DBA分析排查,暂未找到原因。
2. 原因分析
从错误日志中看出,出错都是在内存分配时,在jemalloc下的 throw_bad_castv 抛出 bad_alloc 异常
提示关注下虚拟内存后,同事找出频繁 core 的实例与稳定实例间,系统配置 vm.max_map_count 有所不同。
7. 观察发现,开启jemalloc后虽然物理内存无泄漏,但是虚拟内存仍然存在泄漏现象
通过pmap -x <msyql pid>查看进程使用内存的详细信息
$ pmap -x 739642|grep anon|wc -l --开启jemalloc
24773
$ pmap -x 2876664|grep anon|wc -l --未使用jemalloc
2602
开启J版内存回收的mysqld有大量的anon(匿名内存块),虽然物理内存释放,但是内存映射区仍然保留,且不断增加
怀疑是内存映射区耗尽导致
8. 调整vm.max_map_count 验证
vm.max_map_count默认为65530 ,上次升级5.7.49后曾优化过内核设置vm.max_map_count=262144,所以升级后至今未触发重启
为验证,调小vm.max_map_count,超过内存映射区的mysqld立即重启
以上,mysqld 频繁OOM原因为mysqld进程映射有大量的anon(匿名内存块)导致进程内存映射区耗尽导致
对于开启jemalloc后,mysqld进程映射大量的anon(匿名内存块),虚拟内存泄漏问题仍需进一步分析
找到一个文章分析,与问题完全吻合:
大概意思是,连续的mmap是会合并为一个记录,count还是1,但连续的区域中间部分munmap了,就会分开成两个区域,count增多。意思是碎片化过多了,导致系统限制新映射区创建。
结合用户提供的 maps 文件,可看到用户映射区记录的映射是连续的地址空间,并且使用(rw-p)和释放的(---p) 梅花间竹地存在,符合连续分配后,释放不再使用内存,导致碎片过多情况。
3. 解决方案
调大 max_map_count 可以简单粗暴的解决这个问题。最终结果,将默认数值65530 调大到 262144