首页 > 数据库 >[转帖]数据库系列之MySQL数据库中内存使用分析

[转帖]数据库系列之MySQL数据库中内存使用分析

时间:2024-06-01 09:54:38浏览次数:22  
标签:buffer 数据库 转帖 内存 MySQL VARIABLE schema size

在实际系统环境中,MySQL实例的内存使用随着业务的增长缓慢增长,有些时候并没有及时的释放。本文简要介绍下MySQL数据库中和内存相关的配置,以及分析内存的实际使用情况,以进行应急和调优处理。


1、MySQL内存结构

在MySQL中内存的占用主要由两部分组成:全局共享缓存global buffers和所有线程独立缓存thread buffers。

  • Global buffers主要用于缓存数据页、索引页、数据字典等常用数据,这部分为常驻内存;
  • Thread buffers针对每个数据库连接会话会独立分配缓存,thread buffer与连接数成正比,连接数越高则总的thread buffers占用越高。这部分缓存通常会随着连接的释放而关闭。

MySQL中使用的内存大小等于全局共享缓存(Sharing+innodb_buffer_pool)和所有线程缓存之和,如下图所示:

在这里插入图片描述

1)global_buffers:包括Sharing buffers部分+InnoDB_Buffer_Pool

  • innodb_buffer_pool_size:InnoDB高速缓存,缓存innodb表的索引,数据,插入数据时的缓冲,以及事务锁、自适应哈希等。通过“show engine innodb status \G”和“show global status like ‘innodb_buffer_pool_%’”可以查看innodb_buffer_pool的表现。
  • innodb_log_buffer_size:InnoDB REDO日志缓冲,提高REDO日志写入效率。由于InnoDB在事务提交前,并不将改变的日志写入到磁盘中,因此在大事务中,可以减轻磁盘I/O的压力。
  • innodb_additional_mem_pool_size :用来存放Innodb的内部目录,由系统自动调整。
  • key_buffer_size:指定索引缓冲区的大小,它决定MyISAM表索引处理的速度,尤其是索引读的速度,只对MyISAM表起作用。即使不使用MyISAM表,但是内部的临时磁盘表是MyISAM表,也要使用该值。
  • query_cache_size:查询高速缓存,缓存查询结果,当打开时候,执行查询语句会进行缓存,读写都会带来额外的内存消耗,下次再次查询若命中该缓存会立刻返回结果。
  • table_open_cache:表空间文件描述符缓存,提高数据表打开效率。存放当前已经打开的表句柄,与表创建时指定的存储引擎相关。当把table_open_cache设置的过大时,如果系统处理不了这么多文件描述符,那么就会出现客户端失效、连接不上。
  • table_definition_cache:表定义文件描述符缓存,提高数据表打开效率。MySQL需要打开frm文件,并将其内容初始化为Table Share对象。这里存放与存储引擎无关的,独立的表定义相关信息。

2)all_thread_buffers:max_threads(当前活跃连接数) * (会话级内存分配总和)

  • read_buffer_size:顺序读缓冲,提高顺序读效率。MySQL读入缓冲区的大小,将对表进行顺序扫描的请求将分配一个读入缓冲区,MySQL会为它分配一段内存缓冲区,read_buffer_size变量控制这一缓冲区的大小,如果对表的顺序扫描非常频繁,并你认为频繁扫描进行的太慢,可以通过增加该变量值以及内存缓冲区大小提高其性能。
  • read_rnd_buffer_size:随机读缓冲,提高随机读效率。MySQL的随机读缓冲区大小,当按任意顺序读取行时(列如按照排序顺序)将分配一个随机读取缓冲区,进行排序查询时,MySQL会首先扫描一遍该缓冲,以避免磁盘搜索,提高查询速度,如果需要大量数据可适当的调整该值,但MySQL会为每个客户连接分配该缓冲区所以尽量适当设置该值,以免内存开销过大。
  • sort_buffer_size:排序缓冲,提高排序效率。connection级参数,在每个connection第一次需要使用这个buffer的时候,一次性分配设置的内存。
  • join_buffer_size:表连接缓冲,提高表连接效率。MySQL在完成某些Join需求的时候(all/index join),为了减少参与Join的“被驱动表”的读取次数以提高性能,需要使用到Join Buffer来协助完成 Join操作。
  • binlog_cache_size:二进制日志缓冲,提高二进制日志写入效率为每个session 分配的内存,在事务过程中用来存储二进制日志的缓存,作用是提高记录bin-log的效率。
  • tmp_table_size:内存临时表,提高临时表存储效率。当需要做类似group by操作生成的临时表大小,提高联接查询速度的效果,调整该值直到created_tmp_disk_tables/created_tmp_tables*100% <= 25%。
  • thread_stack:线程堆栈,暂时寄存SQL语句/存储过程、线程运行时的信息等。每个连接线程被创建时,MySQL给它分配的内存大小。当MySQL创建一个新的连接线程时,需要给它分配一定大小的内存堆栈空间,以便存放客户端的请求的Query及自身的各种状态和处理信息。
  • thread_cache_size:线程缓存,降低多次反复打开线程开销。当客户端断开之后,服务器处理此客户的线程将会缓存起来以响应下一个客户而不是销毁(前提是缓存数未达上限)。
  • net_buffer_length:线程持连接缓冲以及读取结果缓冲。客户发出的SQL语句期望的长度,如果语句超过这个长度,缓冲区自动地被扩大,直到max_allowed_packet个字节。
  • bulk_insert_buffer_size:MyISAM表批量写入数据缓冲。如果进行批量插入,可以增加bulk_insert_buffer_size变量值的方法来提高速度,只对myisam表使用。

调整对应的配置后,相应的内存使用大小可以通过计算得到(参考网址http://www.mysqlcalculator.com/):

在这里插入图片描述

另外,也可以通过SQL语句获得各个配置的大小(假设最大连接为200),如下所示:

select VARIABLE_NAME,VARIABLE_VALUE/1024/1024 MB from performance_schema.global_variables WHERE VARIABLE_NAME in ('key_buffer_size','query_cache_size','tmp_table_size','innodb_buffer_pool_size','innodb_additional_mem_pool_size','innodb_log_buffer_size')
union all
SELECT 'sort_buffer_size',(v1.VARIABLE_VALUE*v2.vv) MB
FROM ( select 200 as VARIABLE_VALUE from performance_schema.global_variables WHERE VARIABLE_NAME='MAX_CONNECTIONS' ) AS v1,
  ( SELECT VARIABLE_VALUE/1024/1024 vv FROM performance_schema.global_variables WHERE VARIABLE_NAME = 'sort_buffer_size' ) AS v2 
union all
SELECT 'read_buffer_size',(v1.VARIABLE_VALUE*v2.vv) MB
FROM ( select 200 as VARIABLE_VALUE from performance_schema.global_variables WHERE VARIABLE_NAME='MAX_CONNECTIONS' ) AS v1,
  ( SELECT VARIABLE_VALUE/1024/1024 vv FROM performance_schema.global_variables WHERE VARIABLE_NAME = 'read_buffer_size' ) AS v2 
union all
SELECT 'read_rnd_buffer_size',(v1.VARIABLE_VALUE*v2.vv) MB
FROM ( select 200 as VARIABLE_VALUE from performance_schema.global_variables WHERE VARIABLE_NAME='MAX_CONNECTIONS' ) AS v1,
  ( SELECT VARIABLE_VALUE/1024/1024 vv FROM performance_schema.global_variables WHERE VARIABLE_NAME = 'read_rnd_buffer_size' ) AS v2 
union all
SELECT 'join_buffer_size',(v1.VARIABLE_VALUE*v2.vv) MB
FROM ( select 200 as VARIABLE_VALUE from performance_schema.global_variables WHERE VARIABLE_NAME='MAX_CONNECTIONS' ) AS v1,
  ( SELECT VARIABLE_VALUE/1024/1024  vv FROM performance_schema.global_variables WHERE VARIABLE_NAME = 'join_buffer_size' ) AS v2 
union all
SELECT 'thread_stack',(v1.VARIABLE_VALUE*v2.vv) MB
FROM ( select 200 as VARIABLE_VALUE from performance_schema.global_variables WHERE VARIABLE_NAME='MAX_CONNECTIONS' ) AS v1,
  ( SELECT VARIABLE_VALUE/1024/1024 vv FROM performance_schema.global_variables WHERE VARIABLE_NAME = 'thread_stack' ) AS v2 
union all
SELECT 'binlog_cache_size',(v1.VARIABLE_VALUE*v2.vv) MB
FROM ( select 200 as VARIABLE_VALUE from performance_schema.global_variables WHERE VARIABLE_NAME='MAX_CONNECTIONS' ) AS v1,
  ( SELECT VARIABLE_VALUE/1024/1024 vv FROM performance_schema.global_variables WHERE VARIABLE_NAME = 'binlog_cache_size' ) AS v2

    对于连接配置,可以查看系统中历史最大连接情况进行评估

    mysql> show global status like 'Max_used_connections';
    +----------------------+-------+
    | Variable_name        | Value |
    +----------------------+-------+
    | Max_used_connections | 28    |
    +----------------------+-------+
    1 row in set (0.00 sec)
    
      2、MySQL中内存相关表

      在MySQL中有内存相关的表监控内存的使用情况

      mysql> show tables like '%memory%';
      +-----------------------------------------+
      | Tables_in_performance_schema (%memory%) |
      +-----------------------------------------+
      | 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 |
      +-----------------------------------------+
      5 rows in set (0.00 sec)
      

        以上表的监控统计,分别统计帐户、主机、线程、用户和全局事件执行内存操作等信息。

        1)memory_summary_by_account_by_event_name

        按MySQL账户和事件名称分类的内存使用情况摘要,识别哪些账户正在使用最多的内存,以及这些内存是如何分配的,如查询、系统锁等特定事件。

        select USER, HOST, EVENT_NAME, SUM_NUMBER_OF_BYTES_ALLOC from performance_schema.memory_summary_by_account_by_event_name order by SUM_NUMBER_OF_BYTES_ALLOC desc limit 10;
        

          2)memory_summary_by_host_by_event_name

          按连接到MySQL的主机和事件名称分类的内存使用情况摘要,用来识别识别哪些远程主机或IP地址正在消耗最多的内存。

          select HOST, EVENT_NAME, SUM_NUMBER_OF_BYTES_ALLOC from performance_schema.memory_summary_by_host_by_event_name order by SUM_NUMBER_OF_BYTES_ALLOC desc limit 10;
          

            3)memory_summary_by_thread_by_event_name

            按MySQL线程ID和事件名称分类的内存使用情况摘要,对于特定的长时间运行查询或事务的内存使用情况特别有用,因为每个线程通常与一个特定的查询或事务相关联。

            select thread_id, event_name, SUM_NUMBER_OF_BYTES_ALLOC from performance_schema.memory_summary_by_thread_by_event_name order by SUM_NUMBER_OF_BYTES_ALLOC desc limit 10;
            
            • 1

            得到thread_id后,查找performance_schema.threads表获得对应的processlist_id和processlist_info:

            mysql> select * from performance_schema.threads where THREAD_ID=49\G
            *************************** 1. row ***************************
                      THREAD_ID: 49
                           NAME: thread/sql/one_connection
                           TYPE: FOREGROUND
                 PROCESSLIST_ID: 10
               PROCESSLIST_USER: root
               PROCESSLIST_HOST: tango-DB01
                 PROCESSLIST_DB: tango
            PROCESSLIST_COMMAND: Query
               PROCESSLIST_TIME: 84
              PROCESSLIST_STATE: User sleep
               PROCESSLIST_INFO: select count(1),sleep(2000) from tango.t2 for update
               PARENT_THREAD_ID: NULL
                           ROLE: NULL
                   INSTRUMENTED: YES
                        HISTORY: YES
                CONNECTION_TYPE: SSL/TLS
                   THREAD_OS_ID: 1657
                 RESOURCE_GROUP: USR_default
            1 row in set (0.00 sec)
            

              也可以通过THREAD_ID,查找performance_schema.events_statements_current和performance_schema.events_statements_history获得对应的历史记录信息,定位到具体的SQL语句信息,以后续应急或优化。

              4)memory_summary_by_user_by_event_name

              按MySQL用户和事件名称分类的内存使用情况摘要,更侧重于基于用户名而不是完整的账户信息(包括主机)的内存使用。

              select USER, EVENT_NAME, SUM_NUMBER_OF_BYTES_ALLOC from performance_schema.memory_summary_by_user_by_event_name order by SUM_NUMBER_OF_BYTES_ALLOC desc limit 10;
              
              • 1

              5)memory_summary_global_by_event_name

              包括全局的、不按任何特定账户、主机、线程或用户分类的内存使用情况摘要,提供整个MySQL服务器内存使用的概览,并允许按事件名称来查看这些内存是如何分配的。

              select event_name, SUM_NUMBER_OF_BYTES_ALLOC from performance_schema.memory_summary_global_by_event_name order by SUM_NUMBER_OF_BYTES_ALLOC desc LIMIT 10;
              
                3、MySQL内存分配管理

                MySQL的内存虽然划分为sharing buffers+innodb_buffer_pool和thread buffers,但实际上是按照Server层和innodb层进行内存管理,而且这两部分是按照不同的内存管理方式进行管理的。

                • InnoDB层则主要由Free List、LRU List、FLU List等多个链表来统一管理Innodb_buffer_pool。Innodb_buffer_pool内存初始化是通过「mmap()」方式直接向操作系统申请内存,最终会申请Innodb_buffer_pool_size大小的文件映射段动态内存。「mmap()」方式申请的内存会在文件映射段分配内存,而且在释放时会直接归还系统。这部分内存空间初始化后仅仅是虚拟内存,等真正使用时,才会分配物理内存。
                • Server层是由mem_root来进行内存管理,包括Sharing与Thead buffers。「mem_root」结构体使用内存分配管理器进行内存统一管理,避免频繁调用内存操作,提升性能,统一的分配和管理内存也可以防止发生内存泄漏。

                MySQL首先通过「init_alloc_root」函数初始化一块较大的内存空间,实际上最终是「通过malloc函数向内存分配器申请内存空间」,然后每次再调用alloc_root函数在这块内存空间中分配出内存进行使用,其目的就是将多次零散的malloc操作合并成一次大的malloc操作,以提升性能。

                在Linux中常用的内存分配管理器有三种:ptmalloc(Glibc)、tcmalloc(Google)、jemalloc(FreeBSD)。MySQL 默认使用的是glibc的ptmalloc作为内存分配器。

                • ptmalloc(glibc):ptmalloc是GNU C库(glibc)中的默认内存分配器,广泛用于Linux系统。它提供了一套标准的内存分配和释放函数,如malloc、free、realloc等。ptmalloc通过维护内存池来优化内存分配,并尝试减少内存碎片。然而,由于它是glibc的一部分,因此在某些情况下,其性能可能不如其他专为性能而设计的内存分配器。
                • tcmalloc(Google):tcmalloc用于多线程环境,并通过减少锁的竞争和内存碎片来提高性能。tcmalloc使用线程本地缓存(Thread-Caching Malloc)的概念,将内存分配的任务分散到不同的线程中,以减少对共享数据结构的竞争。此外,tcmalloc还采用了一些优化策略,如小对象合并、高效的分配器缓存等,以进一步提高性能。
                • jemalloc(FreeBSD):jemalloc是由FreeBSD社区开发的一款通用的内存分配器,并逐渐被其他系统广泛采用。jemalloc的设计目标是提供高度可扩展性和低碎片化的内存分配。它使用了一种称为arena的并发数据结构来管理内存,每个arena都有自己的内存池和缓存,以减少锁的竞争。jemalloc还采用了一种称为“大小类”(size classes)的机制来管理不同大小的内存分配请求。它将内存分配请求划分为不同的大小类,并为每个大小类维护一个独立的内存池和缓存。这种机制使得jemalloc在处理不同大小的内存分配请求时具有更高的灵活性和效率。

                在这里插入图片描述

                在实际生产系统中,遇到MySQL实例实际占用的内存比innodb_buffer_pool配置的高很多,但是没有及时释放的现象。大部分是因为内存分配管理器占用很多内存不释放,另一部分是因为内存碎片。另外在部分场景下,原生的MySQL使用的ptmalloc内存管理存在内存释放不及时的问题,所以在基于MySQL系列的国产数据库在内存管理上进行了部分优化,比如使用tcmalloc替代ptmalloc进行内存管理。通过以下命令,也可以查看实际使用的内存管理方式:

                pt-mysql-summary  -S /tmp/mysql.sock --user root --password xxxxxx|grep -A 5 "Memory management"
                # Memory management library ##################################
                jemalloc is not enabled in mysql config for process with id 1339
                # The End ####################################################
                

                  针对ptmalloc(glibc)内存管理的缺陷(调用glibc申请的内存使用完毕后,归还给OS时没有被正常回收,而变成了碎片,随着碎片的不断增长,就能看到mysqld进程占用的内存不断上升)。在测试环境,可以调用gdb函数主动回收释放内存碎片空间:

                  gdb --batch --pid `pidof mysqld` --ex 'call malloc_trim(0)'
                  
                  • 1

                  以上是MySQL数据库内存配置和管理的相关知识。


                  参考资料:

                  1. https://dev.mysql.com/doc/refman/8.0/en/memory-use.html
                  2. https://blog.csdn.net/dc666/article/details/78901341
                  3. https://blog.csdn.net/n88Lpo/article/details/126925517/
                  4. https://zhuanlan.zhihu.com/p/264916825
                  5. https://www.modb.pro/db/60336
                  文章知识点与官方知识档案匹配,可进一步学习相关知识MySQL入门技能树SQL高级技巧CTE和递归查询86634 人正在系统学习中 牧羊人的方向 微信公众号 分享数据库、分布式和容器相关技术

                  标签:buffer,数据库,转帖,内存,MySQL,VARIABLE,schema,size
                  From: https://www.cnblogs.com/jinanxiaolaohu/p/18225578

                  相关文章

                  • Springboot计算机毕业设计亚洲杯志愿者管理系统小程序【附源码】开题+论文+mysql+程序
                    本系统(程序+源码)带文档lw万字以上 文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容研究背景:随着各类大型活动的增多,志愿者管理成为了一个日益重要的问题。特别是在亚洲杯这样的国际性赛事中,高效的志愿者管理系统对于保障活动的顺利进行至关重......
                  • Springboot计算机毕业设计牙科预约微信小程序【附源码】开题+论文+mysql+程序+部署
                    本系统(程序+源码)带文档lw万字以上 文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容研究背景:随着移动互联网的普及和微信平台的广泛应用,微信小程序已成为连接线上线下的重要桥梁。在医疗健康领域,传统的牙科预约方式往往存在着效率低下、操作繁......
                  • [转帖]一次Java内存占用高的排查案例,解释了我对内存问题的所有疑问
                     https://segmentfault.com/a/1190000044152595 原创:扣钉日记(微信公众号ID:codelogs),欢迎分享,非公众号转载保留此声明。问题现象7月25号,我们一服务的内存占用较高,约13G,容器总内存16G,占用约85%,触发了内存报警(阈值85%),而我们是按容器内存60%(9.6G)的比例配置的JVM堆内存......
                  • 如何选择国产数据库?
                    ORACLE的强大是全方位的,作为甲方DBA,喝喝咖啡,看看报纸,开开会,临听一下ORACLEACE吹水!  作为国企的DBA,CTO.基本上国企都算是传统行业,都是跑ERP系统,进销存系统.客户关系系统.基本上都是B2B业务. 直接面对普通老百姓的互联网业务非常少. 核心业务都是使用ORACLE,少量......
                  • windows安装mysql
                    1、官网下载:https://dev.mysql.com/downloads/mysql/  2、解压 3、配置环境变量添加mysql安装的bin文件目录的路径 4、配置初始化的my.ini文件的文件解压后的目录并没有的my.ini文件,没关系可以自行创建在安装根目录下添加的my.ini(新建文本文件,将文件类型改为的.ini),......
                  • 成为MySQL DBA后,再看ORACLE数据库(四、系统视图)
                    在数据库的运维管理中,熟悉数据库系统视图的使用可以帮助我们了解数据库各方面的状态信息。一般数据库的系统视图分为数据字典视图和动态性能视图,数据字典视图用于显示数据库的元数据信息和系统状态信息包括各种数据库对象、用户、角色、权限等;动态性能视图用于显示数据库的性能统......
                  • MySQL基础索引知识【索引创建删除 | MyISAM & InnoDB引擎原理认识】
                      博客主页:花果山~程序猿-CSDN博客文章分栏:MySQL之旅_花果山~程序猿的博客-CSDN博客关注我一起学习,一起进步,一起探索编程的无限可能吧!让我们一起努力,一起成长!目录 一,索引用处二,磁盘三,mysql与磁盘的基本交互单位四,管理page的数据结构(InnoDB引擎下)单个page多个pa......
                  • 用Python脚本迁移MongoDB数据到金仓-kingbase数据库
                    1、首先需要明确MongoDB与kingbase的对应关系,collection相当于table,filed相当于字段,根据这个对应关系创建表;此次迁移的MongoDB里的数据字段是:_id(自动生成的objectid),image(转成二进制存储的文档)所以在金仓里创建表createtableadmin(idvarchar,imagebytea);2、安装Python环境......
                  • 【SQL DB - 关系型数据库是如何工作的】
                    SQLDB-关系型数据库是如何工作的从数据结构说起时间复杂度归并排序二叉搜索树B+树索引哈希表全局概览核心组件工具查询管理器数据管理器:数据查询的流程客户端管理器查询管理器查询解析器查询重写器统计查询优化器索引存取路径联接运算符嵌套循环联接哈希联接合并联接......
                  • MYSQL数据库
                    创建数据库createdatabasemyDB;删除数据库dropdatabasefirstDB;选择数据库usemyDB;创建表mysql>createtablePEOPLE(->IDintAUTO_INCREMENTPRIMARYKEY,->NAMEvarchar(20)notnull,->PASSWORDtinyint(50)notnull,->AGEintno......