背景
前段时间经常收到运维报告数据库服务器内存告警,重启之后,过一段时间又缓慢爬升至峰值。
排查过程
经查询资料发现MySQL官网上找到了这个bug,是因为Mysql默认使用glibc作为内存分配方式的原因。
linux内存管理的三种方式:ptmalloc、tcmalloc、jemalloc,感兴趣的可以自行扩展搜索下。
ptmalloc是glibc默认的内存管理器。使用的是ptmalloc提供的malloc/free函数来分配和释放内存。而这两个函数是由brk或者mmap实现的。当malloc小于128k内存的时候使用的brk(堆内存)来分配,分配内存是是由低地址向高地址,释放内存时是先高地址再低地址按顺序来,所以只有释放了高地址才能释放低地址(也就是后分配的先释放),brk分配容易产生碎片;当malloc大于128k的时候使用的是mmap来分配,mmap释放内存并不需要等待高地址释放后低地址才能释放,而是可以单独去释放,并且释放完成后会归还给操作系统。 brk和mmap都是先申请的虚拟内存,当有查询或者修改操作引发内核缺页中断的时候才会真正的去分配物理内存。
解决方案
1、修改内存分配方式为jemalloc,修改方法参照官方文档
2、使用gdb来释放内存,生产环境谨慎使用:
gdb --batch --pid 你的MySQL进程ID --ex 'call malloc_trim(0)'
3、减少innodb_buffer_pool_size,此方式会影响性能,自行评估业务是否受影响
4、利用shell脚本在空闲时间定时重启数据库,不太推荐,毕竟可能存在应用定时任务