有哪些数据库内存知识点

109次阅读
没有评论

共计 7152 个字符,预计需要花费 18 分钟才能阅读完成。

本篇内容介绍了“有哪些数据库内存知识点”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让丸趣 TV 小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

一、如何看懂内存指标

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

total used free shared buff/cache available Mem: 8008704 5234876 157920 640 2615908 2467292 Swap: 2047 0 2047

第一行是内存数据

1. total:内存总大小,对应于 /proc/meminfo 的 MemTotal

2. used:已使用的内存大小,对应于 /proc/meminfo 的 (MemTotal – MemFree – Buffers – Cached – Slab)

3. free:未使用的内存大小,对应于 /proc/meminfo 的 MemFree

4. buff/cache:已使用的缓存大小,对应于 /proc/meminfo 的 Buffers+Cached

5. available:可供使用的内存大小,这是一个预估值,对应于 /proc/meminfo 的 MemAvailable

第二行是交换分区数据

1. total:交换分区总大小,对应于 /proc/meminfo 的 SwapTotal

2. used:已使用的交换分区,对应于 /proc/meminfo 的 (SwapTotal – SwapFree)

3. free:未使用的的内存大小,对应于 /proc/meminfo 的 SwapFree

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

二、MySQL 如何使用内存

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

全局共享

1. innodb_buffer_pool_size:InnoDB 缓冲池的大小

2. innodb_additional_mem_pool_size:InnoDB 存放数据字典和其他内部数据结构的内存大小,5.7 已被移除

3. innodb_log_buffer_size:InnoDB 日志缓冲的大小

4. key_buffer_size:MyISAM 缓存索引块的内存大小

5. query_cache_size:查询缓冲的大小,8.0 已被移除

线程独占

1. thread_stack:每个线程分配的堆栈大小

2. sort_buffer_size:排序缓冲的大小

3. join_buffer_size:连接缓冲的大小

4. read_buffer_size:MyISAM 顺序读缓冲的大小

5. read_rnd_buffer_size:MyISAM 随机读缓冲的大小、MRR 缓冲的大小

6. tmp_table_size/max_heap_table_size:内存临时表的大小

7. binlog_cache_size:二进制日志缓冲的大小

内存分配器

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

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

三、到底是谁占用了内存

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

开启内存监控

实例启动时开启

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

vi my.cnf performance-schema-instrument= memory/%=ON

禁用方法如下:

vi my.cnf performance-schema-instrument= memory/%=OFF

实例运行时开启

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

mysql  UPDATE performance_schema.setup_instruments SET ENABLED =  YES  WHERE NAME LIKE  memory/%

禁用方法如下:

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:  内存分配次数

C OUNT_FREE:  内存回收次数

S UM_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 的最大值

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

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 就比较异常了,存在内存泄漏的风险;由此可知,通过内存监控表,我们可以快速定位内存异常占用问题。

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

/** @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

/** @file include/hash0hash.h The simple hash table utility Created 5/20/1997 Heikki Tuuri *******************************************************/

四、总结

总的来说,只要我们的操作系统 / 数据库有一个相对合理的配置 (NUMA、swapiness、jemalloc 、innodb_buffer_pool_size 等等),大多数情况是不需要关注内存问题的;  如果非常不幸运地碰到内存占用异常问题,可以通过官方提供的实时监控工具 mdash; mdash; 内存监控表,快速进行定位;  不过需要注意的是,开启内存采集器也会带来一些问题,比如额外的内存占用和性能损耗,一般建议是在系统出现内存问题之后,再重启实例启用,并等待复现。

“有哪些数据库内存知识点”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注丸趣 TV 网站,丸趣 TV 小编将为大家输出更多高质量的实用文章!

正文完
 
丸趣
版权声明:本站原创文章,由 丸趣 2023-07-27发表,共计7152字。
转载说明:除特殊说明外本站除技术相关以外文章皆由网络搜集发布,转载请注明出处。
评论(没有评论)