问
当 MySQL 内存异常上涨, 我们可以通过 performance_schema 观察内存的使用, 我们在 实验5 中进行过介绍。
但我们也会发现操作系统统计的 MySQL 内存用量比 performance_schema 统计的 MySQL 内存用量要多。
那么 MySQL 的内存消耗, 有哪些是不在 performance_schema 统计内的呢?
本期我们设计实验来观察这个问题
实验
我们先安装 google-perftools :
安装后, 可以找到相关的库:
宽油起一个数据库:
记下数据库的启动参数, 并关掉数据库:
我们在数据库启动命令前, 增加两个环境变量 LD_PRELOAD 和 HEAPPROFILE.
其中 LD_PRELOAD 指向刚才我们安装的 tcmalloc 库, HEAPPROFILE 是输出文件的路径.
启动数据库后, 我们看到日志中输出了两个 heap 文件.
我们在数据库中增加一些压力, 还是用我们熟悉的翻倍法:
多做点数据:
观察到输出了更多的 heap 文件:
下面我们安装 pprof 来解析这些 heap 文件.
先下载 golang , 此步骤需要挂代理:
安装 golang :
安装 pprof :
用 pprof 解析我们刚才生成的 heap 文件:
我们让 pprof 生成一个 svg 文件, 我们将 svg 文件放到 Chrome 中打开查看:
图比较大, 每根线都标记了内存的分配流, 我们用红色箭头标注了三个汇集点 (所有的连线都会流向这三个汇集点中的某一个).
其中 pfs_malloc 是可以被 performance_schema 跟踪的内存分配, 而其他两个汇集点则不能.
下面我们将图的一部分放大, 举例来做个大致介绍 (本图中我们用红色箭头增强了原图的连线):
我们可以看到有 16384.53kB 是由 log_allocate_buffer 函数调用 ut_allocator 分配的, 这部分无法被 performance_schema 跟踪到.
查看一下代码, 得知 log_allocate_buffer 是根据 log_buffer_size 参数申请内存的:
查看参数, 证实 log_buffer_size 的配置与我们在图中观察到的内存分配一致:
总结
本实验中, 我们使用了 tcmalloc 作为 MySQL 的内存分配器, 并使用 tcmalloc 提供的 heap dump 功能, 追踪 MySQL 的内存分配。
通过内存分配图, 能让我们直观地理解 MySQL 的内存分配:
我们可以从中观察到 每一部分的内存 是从哪个代码路径进行分配的, 以及哪些内存是 performance_schema 能追踪到的。
此功能对性能影响不大, 可以在生产上比较平稳的使用, 用于探索生产环境的一些内存分配异常。