当前位置: 首页 > 科技观察

关于如何排查MySQL内存泄漏的一些思路

时间:2023-03-20 21:14:47 科技观察

本文转载自微信公众号《数据与云》,作者崔虎龙。转载本文请联系数据和云公众号。MySQL的内存使用量增加了90%!在运维过程中,有50%的几率会遇到此类问题。是一种比较普遍的现象。MySQL内存占用高的原因有很多。常见的原因是使用不当,以及MySQL本身的缺陷。到底是哪方面的问题,需要一一排查。下面介绍故障排除思路:1、需要确认参数配置,内存设置是否合理。MySQL内存分为全局和线程级别:全局内存(如:innodb_buffer_pool_size、key_buffer_size、innodb_log_buffer_size)。线程级内存:(如:thread、read、sort、join、tmp等)只在需要的时候分配,运行完成后释放。线程级内存:线程缓存每个连接到MySQL服务器的线程都需要自己的缓存。Thread_stack(256K,512k)是默认分配的。这些内存在空闲时默认使用。此外还有网络缓存、表缓存等,粗略估计会在1M~3M的情况下。可以通过pmap观察内存变化:mysql>SELECT@@query_cache_size,@@key_buffer_size,@@innodb_buffer_pool_size,@@innodb_log_buffer_size,@@tmp_table_size,@@read_buffer_size,@@sort_buffer_size,@@join_buffer_size,@@read_rnd_buffer_log_size,@@read_rnd_buffer_log_size,@@thread_stack,(SELECTCOUNT(host)FROMinformation_schema.processlistwherecommand<>'Sleep')\G;*********************************1.行**************************@@query_cache_size:1048576@@key_buffer_size:8388608@@innodb_buffer_pool_size:268435456@@innodb_log_buffer_size:8388608@@tmp_table_size:16777216@@read_buffer_size:131072@@sort_buffer_size:1048576@@join_buffer_size:1048576@@read_rnd_buffer_size:2097152@@binlog_cache_size:8388608@@thread_stack:524288(selectcount(host)frominformation_schema.processlistwherecommand'):夨'1query_cache_size版本8.0已被弃用。2.StoredProcedures&Functions&Triggers&Views根据目前积累的经验,存储过程&函数&触发器&视图不适合MySQL场景。性能不好,容易发现内存没有释放的问题,所以建议尽量避免。存储过程和函数MySQL5.7mysql>SELECTdb,type,count(*)FROMmysql.procWHEREDbnotin('mysql','information_schema','performance_schema','sys')GROUPBYdb,type;MySQL8.0mysql>SELECTRoutine_schema,Routine_typeFROMinformation_schema.RoutinesWHERERoutine_schemanotin('mysql','information_schema','performance_schema','sys')GROUPBYRoutine_schema,Routine_type;查看mysql>SELECTTABLE_SCHEMA,COUNT(TABLE_NAME)FROMinformation_schema.VIEWSWHERETABLE_SCHEMAnotin('mysql','information_schema',UPBsys'SCYTAG'ROUNT';触发mysql>SELECTTRIGGER_SCHEMA,count(*)FROMinformation_schema.triggersWHERETRIGGER_SCHEMAnotin('mysql','information_schema','performance_schema','sys')GROUPBYTRIGGER_SCHEMA;以上通过MySQL的配置参数和设计层面检查是否存在内存泄漏的可能,下面我们看看如何分析实际的内存使用情况。3、系统库统计查询总内存使用mysql>SELECTSUM(CAST(replace(current_alloc,'MiB','')asDECIMAL(10,2)))FROMsys.memory_global_by_current_bytesWHEREcurrent_alloclike'%MiB%';事件统计内存mysql>SELECTevent_name,SUM(CAST(replace(current_alloc,'MiB','')asDECIMAL(10,2)))FROMsys.memory_global_by_current_bytesWHEREcurrent_alloclike'%MiB%'GROUPBYevent_nameORDERBYSUM(CAST(replace(current_alloc,'MiB','')asDECIMAL(10,2)))DESC;mysql>SELECTevent_name,sys.format_bytes(CURRENT_NUMBER_OF_BYTES_USED)FROMperformance_schema.memory_summary_global_by_event_nameORDERBYCURRENT_NUMBER_OF_BYTES_USEDDESCLIMIT10;账号级别统计mysql>SELECTuser,event_name,current_number_of_bytes_used/1024/1024asMB_CURRENTLY_USEDFROMperformance_schema.memory_summary_by_account_by_event_nameWHEREhost<>"localhost"ORDERBYcurrent_number_of_bytes_usedDESCLIMIT10;备注:有必要统计用户Levelmemory,becausemanyenvironmentshaveconnectedthird-partyplug-instosimulateslavelibraries,andthese插件容易出现内存故障。线程对应sql语句,内存使用统计SELECTthread_id,event_name,sys.format_bytes(CURRENT_NUMBER_OF_BYTES_USED)FROMperformance_schema.memory_summary_by_thread_by_event_nameORDERBYCURRENT_NUMBER_OF_BYTES_USEDDESCLIMIT20;SELECTm.thread_idtid,m.user,esc.DIGEST_TEXT,m.current_allocated,m.total_allocatedFROMsys.memory_by_thread_by_current_bytesm,performance_schema.events_statements_currentescWHEREm.`thread_id`=esc.THREAD_ID\G开启所有内存性能监控,会影响性能,请注意/%';#查看使用SELECT*FROMperformance_schema.memory_summary_global_by_event_nameWHEREEVENT_NAMELIKE'memory/%'ORDERBYCURRENT_NUMBER_OF_BYTES_USEDDESC;系统表内部存储监控信息选择*来自ys.x$memory_global_total;select*fromperformance_schema.memory_summary_by_account_by_event_name;select*fromperformance_schema.memory_summary_by_host_by_event_name;select*fromperformance_schema.memory_summary_by_thread_by_event_name;select*fromperformance_schema.memory_summary_by_user_by_event_name;select*fromperformance_schema.memory_summary_global_by_event_name;备注:找到对应问题事件或线程后,可以进行排查,解决内存偏高的问题4、查看内存的系统工具1)top命令显示系统中各个进程的资源使用情况。Shift+m??键查看内存排行的实际内存使用情况,注意RES指标。2)free命令free-h命令显示系统内存的使用情况,包括物理内存、交换内存(swap)和内核缓冲内存。使用的列显示已使用的物理内存和交换空间。buff/cache列显示缓冲区和缓存使用的物理内存大小。可用列显示应用程序仍可使用的物理内存量。Swap行(第三行)是交换空间的使用情况。3)ps命令MySQL相关进程的内存使用情况。shell>pseouser,pid,vsz,rss$(pgrep-f'mysqld')USERPIDVSZRSSroot215945129602356mysql2172461291540241824root221056129602428mysql37424313369244087524)pmap命令pmap是Linux调试和运维的一个很好的内存映像工具用法一:执行一段时间记录数据变化,最少20条记录,下面22837是MySQLpidwhiletrue;dopmap-d22837|tail-1;sleep2;done用法二:Linux命令pmapMySQLpid导出内存,下面22837是MySQLpidpmap-X-p22837>/tmp/memmysql.txtRSS是这个进程实际占用的物理内存。Dirty:脏页(包括共享和私有)的字节数。映射:占用内存的文件,或者[anon](分配的内存),或者[stack](堆栈)。writeable/private:进程占用的私有地址空间大小,即进程实际使用的内存大小。1.首先使用/top/free/ps判断是否存在系统级别的内存泄漏。如果是,则可以从顶部输出确定哪个过程。2、pmap工具可以帮助判断进程是否存在内存泄漏。判断内存泄漏的原理:如果writeable/private('pmap-d'输出)在重复操作中一直稳定增长,那么肯定存在内存泄漏。综上所述,对于MySQL内存泄漏:从参数设置和设计上,通过ps库尝试合理检查,进一步确认官方bug中的内存泄漏搜索,是否有修复版本。以上检查没找到原因,可以更换服务器或者主从切换观察。也可以进行版本升级(成本相当高)。如果能提供实际环境,也可以一步步调试,捕获内存变化,判断内存泄漏的原因。然后提交bug,让官方提供修复。作者简介崔虎龙,云和恩墨MySQL技术顾问,长期服务于金融、游戏、物流等行业的数据中心,设计数据存储架构,熟悉数据中心运行管理、自动化运维和管理的流程和规范。维护等。擅长MySQL、Redis、MongoDB数据库高可用设计和运维故障排除、备份恢复、升级迁移、性能优化。自学通过MySQLOCP5.6和MySQLOCP5.7认证。2年以上开发经验,10年数据库运维工作经验,其中8年全职MySQL工作;曾担任项目经理、数据库经理、数据仓库架构师、MySQL技术专家、DBA等职位;相关行业:金融(银行业、财务管理)、物流、游戏、医疗、重工业等。