来新公司前,领导就说了,线上生产环境Mysql库经常会发生日间内存爆掉被killed的情况,结果来到这第一天,第一件事就是要根据线上服务器配置优化配置,同时必须找出现在mysql内存持续增加爆掉的原因,虽然我主业已经不是数据库更不是dba了。
这个业务上基本山算是OLTP,盘中都是很简单的SQL,所以性能上虽然有些SQL有些慢,但看过slow-log和performance_schema,可以忽略不计。
初步了解,应用是java开发的,但是应用端没有出现过OOM的情况,也不见卡死或者越来越慢的情况。
从周一开始查到今天下午,尼玛mysql跟memory leak有关的几乎任何能够查到的buglist都被一个个review验证了,差不多能遇到的各种可能性都测试过,包括但不限于concat可能存在内存分配泄露,google版jemalloc可能导致内存增长,2.6.32版本vm.swappiness=0行为发生变化可能导致内存bug,mysql memory临时表释放可能存在问题,大量表的drop/create会导致dict_mem无限增长,几乎验证了mariadb/percona/mysql社区版本5.5,5.6,5.7各个版本,分析了各种mysql内存组成情况的脚本以及验证工具,尼玛都没找到问题。。。
尝试过将mysql 临时表从memory改到innodb,又改到myisam已验证可能存在问题,均没有发现明显问题。
有帖子又提及LOB可能会释放存在问题,仔细检查发现,业务表没有LOB类型,但似乎有定时任务不停在查询mysql.proc,需要跟开发确认原因。
某个帖子又提及5.0版本中client_statisitics中host超过16导致/tmp空间持续增长导致内存持续增长,我们用的percona server 5.6,经验证后,不是该问题所致。。不过顺带发现一个运维用python写的脚本不停地create/drop连接,要求整改了。。
线上环境基本上所有业务编写在存储过程中,一个过程套用其他五六个存储过程,各种奇葩逻辑。。。无奈只能做到运维旁边守着控制台盯着,已经排除了各种mysql服务器自身导致的问题,且验证了肯定不可能是innodb和其他服务器端可见的内存的问题之后,开始从应用程序入手,基本上连接就50个不到,有差不多一半的连接都是两个定时任务在实时更新风控相关的值,有数据更新程序就整个过程跑,不然就基本上跳过,里面使用了mysql临时表。没数据更新时虽然一直跑,但是mysql内存没有增长,到了盘中有数据之后,内存就每隔几秒nM到一二十M的增长,然后增长到了mysqld的内存占整个OS内存的90%左右,然后top RES维持在该值,VIRT开始继续增长,直到盘后的备份时因为OOM被os killed。盯着看了两天之后,本来昨天就打算在内存90%时逐台应用程序掐掉看下是不是客户端连接导致的,只是运维后来走了。。今天收市后让运维把接入机重启了下,瞬间mysqld内存占用回到了50%。问题的现状总算是可以重现了。
查看了下应用配置并跟框架确认了下,目前用的c3p0。
现在剩下的就是明天继续盯盘检查时c3p0连接配置问题所致,还是mysql临时表问题(在测试环境各个版本都模拟了,都没重现线上问题,估计不是这个问题所致是大概率),要是还不是这两个问题所致, 只能代码慢慢debug优化下去,然后再找到根本原因。
。。。严重吐槽。。。
mysql查看innodb/myisam之外内存使用情况的工具基本上没有。网上的各种什么mysqltuner.pl,my_memory,包括mysql 5.7的memory performance_schema,各种的瞎猜测。。
唯一可靠的估计就是valgrind,可惜没法attach到线上进程。。