问
在 第 44 问 中, 咱们应用 tcmalloc 提供的工具, 来查看 MySQL 的内存调配
该办法对性能影响不大, 能够在生产环境运行, 但须要将 MySQL 的分配器配置成 tcmalloc
在本次试验中, 咱们介绍另外一种办法, 针对于 MySQL 的内存突增状况进行诊断
试验
咱们仍然宽油起一个数据库:
本试验中, 咱们须要模仿 MySQL 的内存突增的状况. 咱们从 MySQL 的 bug 库里找到一个易于复现的相干 bug: https://bugs.mysql.com/bug.ph…
这个 bug 的形容很清晰, 并提供了一个 SQL 脚本, 间接执行该脚本就能够复现内存激增的状况:
咱们来试一下:
以后 MySQL 的内存占用为 181M
执行脚本:
在脚本执行过程中, 咱们会发现 MySQL 应用的内存在一直上涨
当初咱们来诊断 MySQL 对内存的应用. 在脚本执行过程中, 同时执行如下命令进行观测:
小贴士
什么是零碎调用 mmap?
简略来说, MySQL 不是间接向 Linux 申请内存, 而是向 glibc 申请内存. glibc 会维持一个内存池, 当 glibc 发现内存池吃紧时, 会通过零碎调用 mmap(或者 brk) 向 Linux 申请内存.
所以咱们监听系统调用 mmap, 也就监听了 MySQL 在什么状况下须要大量内存 (即什么时候 glibc 的内存池吃紧了)
至于 glibc 内存调配的机制, 可参考浏览: https://sploitfun.wordpress.c…
能够看到在当前目录下生成了 perf.data :
咱们将 perf.data 转换成可读的形式:
简略看一下 perf.out , 咱们会看到每次 mmap 的调用都记录了足够的信息, 包含:
- 图中红色标记的局部, 是要求分配内存的线程号. 有了线程号, 咱们就能够找到是哪个 SQL 在占用内存.
- 图中蓝色标记的局部, 是分配内存的大小
- 图中绿色标记的局部, 是分配内存时的堆栈信息
有了线程号和堆栈信息, 咱们就能够判断是哪个 SQL(或者 MySQL 的哪个外部线程), 在什么状况下要求分配内存
本例中, 咱们判断 29735 号过程, 在 create view 这个操作中, 关上表时须要分配内存
当然, perf.out 文件很长, 大家须要将信息都聚合在一起, 再判断谁是最耗费内存的
局限
本实验所介绍的办法是有局限的: 本办法实用于 MySQL 内存激增的状况, 在其余状况下 (比方内存迟缓并持续增长), 本办法不肯定能观测到精确的信息.
如小贴士所述,MySQL 向 glibc 申请内存 (第一步), glibc 的内存池吃紧时,glibc 再向 Linux 申请内存 (第二步).
在内存激增的状况下, 第一步的产生 大概率会导致 第二步的产生, 咱们观测零碎调用 mmap , 实际上是察看到了第二步的产生, 推导出第一步的起因.
而在内存迟缓增长的状况下, 第一步的产生 小概率会导致 第二步的产生, 导致无奈从第二步推导第一步.
比方: 因为某个起因, 内存迟缓增长, 当 glibc 的内存池行将吃紧时, 产生了其余业务 SQL , 导致这些业务 SQL 触发了 glibc 内存池吃紧, 那么咱们诊断出内存增长的起因是因为业务 SQL , 而真正的起因被藏了起来.
应用本办法时, 心愿大家能留神到这个局限.
对于 MySQL 的技术内容,你们还有什么想晓得的吗?连忙留言通知小编吧!