在 MySQL 5.7下排查内存泄露和 OOM 问题全过程

导读

我的个人网站后台使用的是 MySQL 5.7版本,前段时间经常被oom-kill,借助5.7的新特性,经过一番排查,终于抓到这只鬼。

1、问题现象

我的网站前段时间经常时不时就抽风一下,提示数据库无法连接,提示:

建立数据库连接时出错

本想反正是个人网站,挂就挂了,无所谓啦;也可能是VPS配置太低,访问量一大就容易出问题,忍忍算啦。

后来启荣大师说了一句话:看那木匠做的烂门 😓(⊙﹏⊙)b

于是下决心解决问题,不能再被鄙视啦,作为一个DBA,不能容忍数据库无缘无故挂掉,哪怕是个人VPS也不行 O(∩_∩)O~

2、问题排查

首先,加了个cron任务,每分钟自动检测mysqld进程是否存活,如果没有,就启动之。这也是我们在企业里解决问题的指导思想:尽快找到问题,但在还没确认问题之前,优先保证服务可用性,不管你用啥方法。

接下来,再看MySQL自身的日志,看看能不能找到什么线索。然并卵,啥也没找到,应该是被异常kill的,所以只有mysqld启动过程记录,并没有异常关闭的过程记录。

再排查系统日志,终于看到mysqld进程因为OOM给kill了:

图1

可以看到,mysqld进程消耗了最多内存,被oom-killer选中,给干掉了。

既然是OOM,那我们再看下当时系统整体内存消耗情况:

图2

是不是有明显的内存泄露迹象?不清楚的同学可以先看下面这篇文章普及下:

  • 找到MySQL服务器发生SWAP罪魁祸首好了,现在我们已经基本明确mysqld进程是因为内存泄露,导致消耗大量内存,最终被oom-kill了。那么,我们如何知道mysqld进程究竟什么原因消耗掉内存的,都用哪里去了呢?还好,MySQL 5.7的P_S(performance_schema的简称)集成了这样的功能,能帮助我们很方便的了解这些信息。因此我们执行下面的SQL,就能找到MySQL里到底谁消耗了更多内存:yejr@imysql> select event_name,SUM_NUMBER_OF_BYTES_ALLOC from memory_summary_global_by_event_name order by SUM_NUMBER_OF_BYTES_ALLOC desc LIMIT 10;
    图3我们注意到 “memory/innodb/mem0mem” 消耗的内存最大。再执行下面的SQL,查看都有哪些内部线程消耗了更多内存:yejr@imysql>select event_name, SUM_NUMBER_OF_BYTES_ALLOC from memory_summary_by_thread_by_event_name order by SUM_NUMBER_OF_BYTES_ALLOC desc limit 20;
    图4我们注意到,上面的结果中,有很多非MySQL内部后台线程(thread_id 值比较大)用到了 “memory/innodb/mem0mem”,并且内存消耗也比较大。看到这种现象,我的第六感告诉我,应该是并发线程太高或者线程分配不合理所致。因为前端是PHP短连接,不是长连接,不应该有这么多thread,推测是多线程连接或线程池引起的。于是排查了一圈和线程、连接数相关的参数选项及状态,基本确认应该是开了线程池(thread pool),导致了内存泄露,持续消耗内存,最终mysqld进程消耗过多内存,被系统给oom-kill了。下面是我的thread pool相关设置:
    图5当我们把线程池功能关闭后,内存泄露的问题也随之消失,mysqld进程再也没有被oom-kill了,看起来确实是解决的问题。经过几次反复测试,最终观察到以下结论:
  • 同时开着P_S和thread pool会导致发生内存泄露;
  • 同时开着P_S和thread pool,不过采用”one-thread-per-connection”模式而非”pool-of-threads”模式(只用到extra port功能),不会发生内存泄露;
  • 只开着P_S,不开thread pool,不会发生内存泄露;
  • 不开P_S,只开thread pool,也不会发生内存泄露;
  • 同时关闭P_S和thread pool,也不会发生内存泄露;

交代下,我的MySQL版本是:

  • 5.7.17-11-log Percona Server (GPL), Release 11, Revision f60191c更早之前用官方的5.7.13版本也是有问题的。3、结论及建议在前端应用经常有突发短连接或相似场景中,开启线程池对缓解用户连接请求排队有很大帮助,可以避免MySQL连接瞬间被打满、打爆的问题。但线程池也并非适用于全部场景,像本案例遇到的问题就不适合了(我当初开thread pool更多是为了extra port功能)。上面我们提到,从MySQL 5.7版本开始,新增了很多有用的视图,可以帮助我们进一步了解MySQL内部发生的一些事情。在P_S中新增了下面这几个内存相关的视图:
  • memory_summary_by_account_by_event_name
  • memory_summary_by_host_by_event_name
  • memory_summary_by_thread_by_event_name
  • memory_summary_by_user_by_event_name
  • memory_summary_global_by_event_name

看视图的名字,就知道这可以帮助我们分别从账号(包含授权主机信息)、主机、线程、用户(不包含授权主机信息)、整体全局等多个角度查看内存消耗统计。

除了内存统计,还有和事务、复制相关的一些视图,并且原来有些视图也进一步增强。

在MySQL 5.7中,还集成了sys schema,关于sys schema大家可以看本文下方的推荐链接。sys schema主要是对Information_schema以及Performance_Schema的视图进一步增强处理,提高结果的可读性。比如,我们可以查看当前实例总消耗的内存,以及内存主要由哪些部分给占用了,也可以透过sys schema来查看:

图6

建议大家应该花些时间好好再深入理解下I_S、P_S、sys schema,对我们这些非底层代码的MySQL DBA而言,这些都是很好的辅助手段。

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

编辑于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏数据和云

MySQL DBA之路 | 性能配置调优篇

一、简介 数据库服务器需要CPU、内存、 磁盘和网络才能运行,了解这些资源对于DBA来说非常重要,因为任何的超载行为都可能成为限制因素,导致数据库服务器性能不佳...

4006
来自专栏weixuqin 的专栏

基于 Django 的手机管理系统

1604
来自专栏微服务生态

论代码级性能优化变迁之路(一)

大家好,很久没有和大家一起讨论技术了,那么今天我将和大家一起探讨我负责的某项目的性能变迁之路。

742
来自专栏Golang语言社区

Web 最常见安全知识总结

随着Web2.0、网络社交等一系列新型的互联网产品的诞生,基于Web环境的互联网应用越来越广泛,企业信息化的过程中,越来越多的应用都架设在Web平台上。Web业...

34912
来自专栏pangguoming

(十一) 整合spring cloud云架构 - SSO单点登录之OAuth2.0登录流程(2)

上一篇是站在巨人的肩膀上去研究OAuth2.0,也是为了快速帮助大家认识OAuth2.0,闲话少说,我根据框架中OAuth2.0的使用总结,画了一个简单的流程图...

1362
来自专栏极客编程

用Node操作Firebird

  Firebird是一个跨平台的关系数据库系统,目前能够运行在Windows、linux和各种Unix操作系统上,提供了大部分SQL-99标准的功能。它既能作...

602
来自专栏漏斗社区

代码审计| APPCMS SQL-XSS-CSRF-SHELL

0x01 背景 由若水师傅提供的一个素材,想要复现CNVD上披露的一个APPCMS的漏洞,由CNVD上的描述可以知道存在漏洞的地方是comment.php这个...

40211
来自专栏喔家ArchiSelf

老曹眼中的MySQL调优

对于全栈而言,数据库技能不可或缺,关系型数据库或者nosql,内存型数据库或者偏磁盘存储的数据库,对象存储的数据库或者图数据库……林林总总,但是第一必备技能还应...

1053
来自专栏杨建荣的学习笔记

MySQL 5.5复制升级到5.7的一点简单尝试

最近有个需求是升级MySQL 5.5到MySQL 5.7版本,为此我们想了一些方案,比如MySQL级联复制升级,这么考虑主要是基于版本的差异性,尽可能保...

5047
来自专栏北京马哥教育

LINUX上MYSQL优化三板斧

云豆贴心提醒,本文阅读时间7分钟 现在MySQL运行的大部分环境都是在Linux上的,如何在Linux操作系统上根据MySQL进行优化,我们这里给出一些通用简...

2757

扫码关注云+社区