Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >MySQL最佳实践:内存管理分析

MySQL最佳实践:内存管理分析

原创
作者头像
brightdeng@DBA
修改于 2020-12-29 13:27:46
修改于 2020-12-29 13:27:46
11.9K00
代码可运行
举报
运行总次数:0
代码可运行

前言

在日常工作中,时不时会收到内存使用率高的告警,那么我们应该如何处理呢?本文将从LinuxMySQL两个层面,介绍内存管理的相关知识点,希望能给大家带来一些帮助,以便更好地应对内存问题。

如何看懂内存指标

遇到内存问题,可以先通过free、vmstat、top等命令,进行检查。free命令,可以获取系统内存的总体使用情况;vmstat命令,可以实时观察内存的变化情况;top命令,可以进行排序,获取内存占用大的进程。这里简单介绍一下free命令输出(以CentOS 7为例):

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
              total        used        free      shared  buff/cache   available
Mem:        8008704     5234876      157920         640     2615908     2467292
Swap:          2047           0        2047

第一行是内存数据

  • total:内存总大小,对应于/proc/meminfo的MemTotal
  • used:已使用的内存大小,对应于/proc/meminfo的(MemTotal - MemFree - Buffers - Cached - Slab)
  • free:未使用的内存大小,对应于/proc/meminfo的MemFree
  • buff/cache:已使用的缓存大小,对应于/proc/meminfo的Buffers+Cached
  • available:可供使用的内存大小,这是一个预估值,对应于/proc/meminfo的MemAvailable

第二行是交换分区数据

  • total:交换分区总大小,对应于/proc/meminfo的SwapTotal
  • used:已使用的交换分区,对应于/proc/meminfo的(SwapTotal - SwapFree)
  • free:未使用的的内存大小,对应于/proc/meminfo的SwapFree

这里值得注意的是,Linux操作系统会最大限度利用内存,空闲内存free少,不代表系统内存不够用了。个人建议,一方面需要观察内存增长的整体趋势是否逐渐趋于平稳、以及used和buff/cache的变化情况;另一方面需要观察是否频繁使用到交换分区swap,当然了,这里要避免NUMA和swapiness设置不正确带来的干扰。

MySQL如何使用内存

在MySQL中,内存占用主要包括以下几部分,全局共享的内存、线程独占的内存、内存分配器占用的内存,具体如下:

全局共享

  • innodb_buffer_pool_size:InnoDB缓冲池的大小
  • innodb_additional_mem_pool_size:InnoDB存放数据字典和其他内部数据结构的内存大小,5.7已被移除
  • innodb_log_buffer_size:InnoDB日志缓冲的大小
  • key_buffer_size:MyISAM缓存索引块的内存大小
  • query_cache_size:查询缓冲的大小,8.0已被移除

线程独占

  • thread_stack:每个线程分配的堆栈大小
  • sort_buffer_size:排序缓冲的大小
  • join_buffer_size:连接缓冲的大小
  • read_buffer_size:MyISAM顺序读缓冲的大小
  • read_rnd_buffer_size:MyISAM随机读缓冲的大小、MRR缓冲的大小
  • tmp_table_size/max_heap_table_size:内存临时表的大小
  • binlog_cache_size:二进制日志缓冲的大小

内存分配器

在MySQL中,buffer pool的内存,是通过mmap()方式直接向操作系统申请分配;除此之外,大多数的内存管理,都需要经过内存分配器。为了实现更高效的内存管理,避免频繁的内存分配与回收,内存分配器会长时间占用大量内存,以供内部重复使用。关于内存分配器的选择,推荐使用jemalloc,可以有效解决内存碎片与提升整体性能。

因此,MySQL占用内存高的原因可能包括:innodb_buffer_pool_size设置过大、连接数/并发数过高、大量排序操作、内存分配器占用、以及MySQL Bug等等。一般来说,在MySQL整个运行周期内,刚启动时内存上涨会比较快,运行一段时间后会逐渐趋于平稳,这种情况是不需要过多关注的;如果在稳定运行后,出现内存突增、内存持续增长不释放的情况,那就需要我们进一步分析是什么原因造成的。

到底是谁占用了内存

在绝大多数情况下,我们是不需要花费过多精力,去关注MySQL内存使用情况的;但是,也不能排除确实存在内存占用异常的情况,这个时候我们应该如何去进行深入排查呢?其实,MySQL官方就提供了强大的实时监控工具——performance_schema库下的监控内存表,通过这个工具,我们可以很清晰地观察到MySQL内存到底是被谁占用了、分别占用了多少。

开启内存监控

  • 实例启动时开启

我们可以选择,在实例启动时,开启内存监控采集器,具体方法如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
vi my.cnf
performance-schema-instrument='memory/%=ON'

禁用方法如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
vi my.cnf
performance-schema-instrument='memory/%=OFF'
  • 实例运行时开启

我们也可以选择,在实例运行时,动态开启内存监控采集器,具体方法如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
mysql> UPDATE performance_schema.setup_instruments SET ENABLED = 'YES' WHERE NAME LIKE 'memory/%';

禁用方法如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
mysql> UPDATE performance_schema.setup_instruments SET ENABLED = 'NO' WHERE NAME LIKE 'memory/%';

因为采集器的实现原理,是在内存进行分配/回收时,更新相对应内存监控表的数据;换句话说,就是采集器只能监控到开启之后的内存使用情况;而MySQL很大一部分内存都是在实例启动时就预先分配的,因此要想准确监控实例的内存使用率,需要在实例启动时就开启内存采集器。

内存监控表

在performance_schema库下,提供多个维度的内存监控表,具体如下:

  • 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:全局纬度的内存监控表

内存监控表均包括以下关键字段:

  • COUNT_ALLOC:内存分配次数
  • COUNT_FREE:内存回收次数
  • SUM_NUMBER_OF_BYTES_ALLOC:内存分配大小
  • SUM_NUMBER_OF_BYTES_FREE:内存回收大小
  • CURRENT_COUNT_USED:当前分配的内存,通过COUNT_ALLOC-COUNT_FREE计算得到
  • CURRENT_NUMBER_OF_BYTES_USED:当前分配的内存大小,通过SUM_NUMBER_OF_BYTES_ALLOC-SUM_NUMBER_OF_BYTES_FREE计算得到
  • LOW_COUNT_USED:CURRENT_COUNT_USED的最小值
  • HIGH_COUNT_USED:CURRENT_COUNT_USED的最大值
  • LOW_NUMBER_OF_BYTES_USED:CURRENT_NUMBER_OF_BYTES_USED的最小值
  • HIGH_NUMBER_OF_BYTES_USED:CURRENT_NUMBER_OF_BYTES_USED的最大值

接下来,让我们看一个正常运行实例的内存使用情况,具体如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
mysql> select USER,HOST,EVENT_NAME,COUNT_ALLOC,COUNT_FREE,CURRENT_COUNT_USED,SUM_NUMBER_OF_BYTES_ALLOC,SUM_NUMBER_OF_BYTES_FREE,CURRENT_NUMBER_OF_BYTES_USED from performance_schema.memory_summary_by_account_by_event_name order by CURRENT_NUMBER_OF_BYTES_USED desc limit 10;
+------+-----------+----------------------------+-------------+------------+--------------------+---------------------------+--------------------------+------------------------------+
| USER | HOST      | EVENT_NAME                 | COUNT_ALLOC | COUNT_FREE | CURRENT_COUNT_USED | SUM_NUMBER_OF_BYTES_ALLOC | SUM_NUMBER_OF_BYTES_FREE | CURRENT_NUMBER_OF_BYTES_USED |
+------+-----------+----------------------------+-------------+------------+--------------------+---------------------------+--------------------------+------------------------------+
| NULL | NULL      | memory/innodb/buf_buf_pool |          32 |          0 |                 32 |                4500488192 |                        0 |                   4500488192 |
| NULL | NULL      | memory/innodb/os0event     |     1573559 |          0 |            1573559 |                 214004024 |                        0 |                    214004024 |
| NULL | NULL      | memory/innodb/hash0hash    |          82 |          6 |                 76 |                 397976480 |                227067024 |                    170909456 |
| NULL | NULL      | memory/innodb/log0log      |          10 |          0 |                 10 |                  33565840 |                        0 |                     33565840 |
| root | localhost | memory/innodb/std          |     3650638 |    3043111 |             607527 |                 160778066 |                141334898 |                     19443168 |
| NULL | NULL      | memory/mysys/KEY_CACHE     |           3 |          0 |                  3 |                   8390768 |                        0 |                      8390768 |
| NULL | NULL      | memory/innodb/ut0pool      |           2 |          0 |                  2 |                   4194480 |                        0 |                      4194480 |
| NULL | NULL      | memory/innodb/sync0arr     |           3 |          0 |                  3 |                   2506184 |                        0 |                      2506184 |
| NULL | NULL      | memory/innodb/lock0lock    |          33 |          0 |                 33 |                   2245040 |                        0 |                      2245040 |
| root | localhost | memory/innodb/mem0mem      |     9897784 |    9896793 |                991 |                8845389160 |               8843147749 |                      2241411 |
+------+-----------+----------------------------+-------------+------------+--------------------+---------------------------+--------------------------+------------------------------+
10 rows in set (0.01 sec)

再看一个Bug #86821的场景,buffer pool占用最大内存正常,但是存储过程占用3GB就比较异常了,存在内存泄漏的风险;由此可知,通过内存监控表,我们可以快速定位内存异常占用问题。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
mysql> select event_name, current_alloc, high_alloc from memory_global_by_current_bytes where current_count > 0;
+--------------------------------------------------------------------------------+---------------+-------------+
| event_name                                                                     | current_alloc | high_alloc  |
+--------------------------------------------------------------------------------+---------------+-------------+
| memory/innodb/buf_buf_pool                                                     | 7.29 GiB      | 7.29 GiB    |
| memory/sql/sp_head::main_mem_root                                              | 3.21 GiB      | 3.62 GiB    |
| memory/innodb/hash0hash                                                        | 210.16 MiB    | 323.63 MiB  |
| memory/sql/TABLE                                                               | 183.82 MiB    | 190.28 MiB  |
| memory/sql/Query_cache                                                         | 128.02 MiB    | 128.02 MiB  |
| memory/mysys/KEY_CACHE                                                         | 64.00 MiB     | 64.00 MiB   |
| memory/innodb/log0log                                                          | 32.08 MiB     | 32.08 MiB   |
| memory/innodb/parallel_doublewrite                                             | 30.27 MiB     | 30.27 MiB   |
| memory/performance_schema/table_handles                                        | 27.19 MiB     | 27.19 MiB   |
| memory/innodb/mem0mem                                                          | 19.14 MiB     | 20.79 MiB   |
| memory/performance_schema/events_statements_history_long                       | 13.66 MiB     | 13.66 MiB   |
| memory/performance_schema/events_statements_summary_by_digest.tokens           | 9.77 MiB      | 9.77 MiB    |

另外,如果我们在内存监控表,看见一些比较陌生的event,可以翻阅官方文档或源码,继续进一步解读,例如

memory/innodb/os0event

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 /** @file include/os0event.h
  The interface to the operating system condition variables
 
  Created 2012-09-23 Sunny Bains (split from os0sync.h)
  *******************************************************/

memory/innodb/hash0hash

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 /** @file include/hash0hash.h
  The simple hash table utility
 
  Created 5/20/1997 Heikki Tuuri
  *******************************************************/

总结

总的来说,只要我们的操作系统/数据库有一个相对合理的配置(NUMA、swapiness、jemalloc

、innodb_buffer_pool_size等等),大多数情况是不需要关注内存问题的;如果非常不幸运地碰到内存占用异常问题,可以通过官方提供的实时监控工具——内存监控表,快速进行定位;不过需要注意的是,开启内存采集器也会带来一些问题,比如额外的内存占用和性能损耗,一般建议是在系统出现内存问题之后,再重启实例启用,并等待复现。

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

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

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

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

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
原创|MySQL performance_schema之内存监控
提示:公众号展示代码会自动折行,建议横屏阅读 背景 无论从使用、研发还是运维的角度,内存监控一直是MySQL的重点之一。完善的内存监控手段有很多作用,包括但不限于: 发现内存泄漏,避免MySQL实例内存耗尽 对实例的运行状态进行定量分析 资源管控和优化 但内存监控想要“完善”并不是那么简单的事。 PFS内存监控介绍 在PFS中,一共有五张内存相关的监控表,每张表会从不同维度收集和聚合内存事件。 memory_summary_by_account_by_event_name: 从用户和连接host的角度统
腾讯数据库技术
2022/10/08
2K0
原创|MySQL performance_schema之内存监控
内存分配统计视图 | 全方位认识 sys 系统库
在上一篇《按 file 分组统计视图 | 全方位认识 sys 系统库》中,我们介绍了sys 系统库中按 file 分组统计的视图,本期的内容将为大家介绍内存事件和innodb buffer pool内存分配的统计视图。下面请跟随我们一起开始 sys 系统库的系统学习之旅吧。
沃趣科技
2018/09/04
1.8K0
内存分配统计视图 | 全方位认识 sys 系统库
关于MySQL内存泄露如何排查的一些思路
MySQL使用内存上升90%!在运维过程中50%的几率,会碰到这样的问题。算是比较普遍的现象。
数据和云
2021/08/27
2.7K0
关于MySQL内存泄露如何排查的一些思路
翻译| 如何排查MySQL 内存泄漏
对crash的数据库进行故障分析并不是一件快乐的事情,尤其是 MySQL 的日志中没有提供 crash 原因的情形。比如当 MySQL 内存耗尽。在 2012年 Peter Zaitsev 写了一篇文章 分析MySQL如何使用内存
用户1278550
2021/09/28
2.5K0
MySQL内存到底消耗在哪里?
一说起MySQL使用的内存,你可能会想到各种buffer,最著名的莫过于innodb buffer pool了,它是内存使用的大户,还有sort buffer等等。除了这些buffer之外,可能还有一些细枝末节,今天我们来总结一下。
AsiaYe
2021/12/04
3.2K0
事件统计 | performance_schema全方位介绍
在上一篇 《事件记录 | performance_schema全方位介绍"》中,我们详细介绍了performance_schema的事件记录表,恭喜大家在学习performance_schema的路上度过了两个最困难的时期。现在,相信大家已经比较清楚什么是事件了,但有时候我们不需要知道每时每刻产生的每一条事件记录信息, 例如:我们希望了解数据库运行以来一段时间的事件统计数据,这个时候就需要查看事件统计表了。今天将带领大家一起踏上系列第四篇的征程(全系共7个篇章),在这一期里,我们将为大家全面讲解performance_schema中事件统计表。统计事件表分为5个类别,分别为等待事件、阶段事件、语句事件、事务事件、内存事件。下面,请跟随我们一起开始performance_schema系统的学习之旅吧。
沃趣科技
2018/07/02
2K0
事件统计 | performance_schema全方位介绍
MySQL 内存那点事你还不会--PS分析+自动历史SQL分析(2)
上期MySQL的分析和自动脚本的基础是基于MySQL的show engine innodb status;
AustinDatabases
2025/03/07
990
MySQL  内存那点事你还不会--PS分析+自动历史SQL分析(2)
MYSQL 8 内存使用分析到底我的内存都跑哪了
人生可悲的事情是,你不知道问题如何解决,并且困惑中, 而更可悲的是,你根本就不知道自己不知道, 当然从另一个角度,那也是一种"幸福".
AustinDatabases
2021/03/16
4.5K0
MYSQL  8 内存使用分析到底我的内存都跑哪了
MySQL内置数据库performance_schema详解(六):监视内存使用的表介绍
performance_schema 是 MySQL 数据库中的一个内置的系统数据库,最早从MySQL5.5版本产生,这个数据库主要用于收集和存储与数据库性能相关的统计信息和指标。
小明互联网技术分享社区
2023/12/27
9290
MySQL内置数据库performance_schema详解(六):监视内存使用的表介绍
MySQL OOM(内存溢出)的排查思路及优化方法
大部分情况下,会杀掉导致OOM的进程,然后系统恢复。通常我们会添加对内存的监控报警,例如:当memory或swap使用超过90%时,触发报警通知,需要及时介入排查。
MySQL轻松学
2019/08/01
9.9K0
TDSQL-C OOM 优化
OOM是实例使用内存超过实例规格内存上限导致进程被kill,实例存在秒级的不可用。MySQL的内存管理比较复杂,内存监控需要开启performance schema查询(默认关闭),会带来额外的内存消耗和性能损失,在不开启performance schema情况下排查内存使用情况又比较困难。本文将基于TDSQL-C(基于MySQL5.7)总结一下在线上经常出现的一些OOM的场景、排查手段及相应的优化方案。 ---- 一、MySQL线上常见OOM问题 1.1 表数量较多导致innodb数据字典内存占用多 查
腾讯数据库技术
2023/02/03
1.7K0
TDSQL-C OOM 优化
MySQL8.0之内存消耗关键因素
在MySQL8.0在启动的时候,会配置各种各样的buffer和cache来提高数据库的性能。如果我们在一台服务器上配置了MySQL8.0的服务,那么这台服务器的内存会同时被操作系统、MySQL8.0服务、以及其他应用程序所共享。
AsiaYe
2021/03/13
3.3K0
Mysql 监控 performance_schema 拿得起,放不下(2)
接上期说,在MYSQL 5.7 后performance_schema 以及后来的sys库的重要性越来越高,各种系统的性能以及系统资源的分配信息都会在这里体现。
AustinDatabases
2020/09/18
8660
MySQL性能诊断-内存
* 需开启所有的memory类型的instruments:update setup_instruments set enabled='yes' where name like '%memory/%';
laosu
2021/03/12
1.9K0
MySQL性能诊断-内存
技术分享 | MySQL 内存管理初探
本文来源:原创投稿 *爱可生开源社区出品,原创内容未经授权不得随意使用,转载请联系小编并注明来源。
爱可生开源社区
2020/10/22
2.9K0
技术分享 | MySQL 内存管理初探
MYSQL优化
本文主要参考官网的优化 https://dev.mysql.com/doc/refman/5.7/en/optimization.html
大大刺猬
2022/11/09
1K0
MySQL内存溢出问题:故障排除指南
在本文中,我将向您展示如何使用新版本的MySQL(5.7+),以及如何更容易地解决 MySQL内存分配中出现的问题。
程序你好
2018/07/23
6.1K0
MySQL内存溢出问题:故障排除指南
故障分析 | MySQL 耗尽主机内存一例分析
开发人员反馈,有一台服务器内存几乎被 MySQL 耗尽了,执行 top 命令,输出如下:
爱可生开源社区
2022/07/05
1.3K0
技术分享 | InnoDB Cluster 如何高效加载数据
爱可生南区负责人兼技术服务总监,MySQL ACE,擅长数据库架构规划、故障诊断、性能优化分析,实践经验丰富,帮助各行业客户解决 MySQL 技术问题,为金融、运营商、互联网等行业客户提供 MySQL 整体解决方案。
爱可生开源社区
2020/03/13
7980
技术分享 | MySQL 并行 DDL
爱可生 DBA 团队成员,会变身,主要负责 MySQL 故障处理和 SQL 审核优化。对技术执着,为客户负责。
爱可生开源社区
2022/04/06
1.3K0
相关推荐
原创|MySQL performance_schema之内存监控
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验