线上mysql内存持续增长直至内存溢出被killed分析

来新公司前,领导就说了,线上生产环境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到线上进程。。

时间: 2024-11-06 14:50:25

线上mysql内存持续增长直至内存溢出被killed分析的相关文章

线上MYSQL同步报错故障处理总结(转)

前言 在发生故障切换后,经常遇到的问题就是同步报错,数据库很小的时候,dump完再导入很简单就处理好了,但线上的数据库都150G-200G,如果用单纯的这种方法,成本太高,故经过一段时间的摸索,总结了几种处理方法. 生产环境架构图 目前现网的架构,保存着两份数据,通过异步复制做的高可用集群,两台机器提供对外服务.在发生故障时,切换到slave上,并将其变成master,坏掉的机器反向同步新的master,在处理故障时,遇到最多的就是主从报错.下面是我收录下来的报错信息. 常见错误 最常见的3种情

记一次线上mysql主从架构异常的恢复经历

前提:之前一位同事负责的一位客户,因后期转到devops小组.所以将此用户交接给我,在后期发现有一套数据库主从环境,从库已经无法正常使用.查看slave 状态为: 其中:Master_Log_File:#此处显示的bin-log已经在master上找不见了Read_Master_Log_Pos:#显示的行数也就存在没有意义了Slave_IO_Running:NO #salve io进程显示为no,无法从master同步数据因此判定从库已经无法使用,需要及时修复.保证主从架构正常使用. 以下是恢复

一则线上MySql连接异常的排查过程

Mysql作为一个常用数据库,在互联网系统应用很多.有些故障是其自身的bug,有些则不是,这里以前段时间遇到的问题举例. 问题 当时遇到的症状是这样的,我们的应用在线上测试环境,JMeter测试过程中,发现每次压力测试开始时访问低前几个http request请求会超时,而之后的请求持续测试中都不会.最后一点是Tomcat的log并没有报什么错误. 压测的内容就是起200线程不停的向这个http页面发送请求,这个页面逻辑也比较简单,会在后端向数据库插入一条数据,连接池采用阿里的Druid(这个坑

如何有效的跟踪线上 MySQL 实例表和权限的变更

介绍 从系统管理员或 DBA 的角度来讲, 总期望将线上的各种变更限制在一个可控的范围内, 减少一些不确定的因素. 这样做有几点好处: 1. 记录线上的库表变更; 2. 对线上的库表变更有全局的了解; 3. 如果有问题, 方便回滚操作; 从这三点来看, 有很多种方式可以实现, 比如通过 migrate 等工具强制所有的操作都以统一的方式执行, 这需要开发人员做更多的配合, 所以这类工具在非规模话的业务场景中较难实现; 另外管理员或 DBA 也可以通过知识库比如 redmine 等类似的方式记录变

记一次线上MySQL数据库死锁问题

最近线上项目报了一个MySQL死锁(DealLock)错误,虽说对业务上是没有什么影响的,由于自己对数据库锁这块了解不是很多,之前也没怎么的在线上碰到过.这次刚好遇到了,便在此记录一下. 出现死锁问题背景 项目层面:报错的项目做的是一个批量下单的动作,会同时写入多条订单数据,代码之前写的是一个事务中一个循环一条一条insert到数据库(至于为啥没用批量插入就不追究了,历史原因了). 数据库层面:一张test表(非线上真实表),比较重要的是有一个 type 和 name的唯一索引. 事务隔离级别:

线上MySQL某个历史数据表的分区笔记

背景: 线上的一个历史数据库,业务方反馈经常遇到一个范围查询就导致CPU迅速飙升的情况.拿到他们提供的SQL后,SQL类似下面这种: select * from `order_his` where `xxxx` = '222' AND `XXXX` <> 1 AND order_time > '2016-11-01 00:00:00' AND order_time < '2017-06-01 00:00:00' \G explain看了下发现基本上是全表扫描了,效率太低了,并且他们

通过SSH秘钥登录线上MySQL数据库(基于Navicat)

前言 生产环境的数据库往往需要经过严格的安全限制,所以禁用密码登录,使用秘钥的方式是一种相对安全的登录方式. 原理: 角色: 主机A:其他主机,有访问线上数据库的权限 主机B:线上数据库的主机 主机C:本机电脑,无访问线上数据库的权限 在本机C上(无访问B的权限),通过ssh配置的主机A(有访问B的权限),访问Navicat常规配置的主机B,即以A的身份连接使用B. 前期准备 生成ssh密钥对.可参考前期博文:快速通道 Navicat配置登录 1.连接的主机配置,如果连接的是线上数据库,就用线上

线上MYSQL同步报错故障处理方法总结

前言 在发生故障切换后,经常遇到的问题就是同步报错,下面是最近收集的报错信息. 记录删除失败 在master上删除一条记录,而slave上找不到 Last_SQL_Error: Could not execute Delete_rows event on table hcy.t1; Can't find record in 't1', Error_code: 1032; handler error HA_ERR_KEY_NOT_FOUND; the event's master log mysq

线上MySQL备份脚本

最近在研究数据库备份,定时执行备份任务,这里直接把备份脚本设置为crontab命令定时执行,脚本内容如下: [[email protected] ~]# cat mysql-backup.sh #!/bin/bash dbpwd='possw0rd123' dbuser=root host=127.0.0.1 port=3306 dbarg=" -u$dbuser -p$dbpwd -h$host -P$port --default-character=utf8 " DATE=`dat