概述
关于MySQL OOM的排查思路
服务器发生内存泄露
- 如何确认服务器发生内存泄漏:
- 一般执行free -m就查看内存的使用情况就可以了。假如cached和used的值相差特别大的话,安么这个时候我们可以认为发生了内存泄漏。(一般在CentOS6的版本上面可以这么认为,但是这个说法暂时还没有一个比较可信的依据)
- buffer和cache的区别:
- buffer: 缓冲,为了提高内存和硬盘之间的数据交换的速度而设计的,是即将要写入磁盘的。
- cache: 缓存,是为了提高CPU和内存之间的数据交换速度而设计的,也就是平常见到的一级缓存,二级缓存,三级缓存,cache是从被磁盘中读出来的。
- 内存使用情况的计算方式()
- total = used+free
- buffer和cache是包含在used内的
- buffer和cache可能是被分配出去,但是实际可能有部分cache或者buffer没有被使用
- -/+ buffer/cache 这行中used是实际使用的内存,free是实际可使用的空闲内存
[root@t-filter1 liuhuang]# free -m
total used free shared buffers cached
Mem: 7870 2567 5302 0 584 1083
-/+ buffers/cache: 898 6971
Swap: 2047 1262 785
[root@t-filter1 liuhuang]#
- 内存泄漏一些应急处理情况(特指MySQL)
- 选择重启进程,彻底释放内存归还给OS
- 找到代码中导致泄漏的代码,并加以修复
- 升级程序版本,通常新版本会解决旧版本的问题
MySQL查看内存泄露
MySQL5.7的库performance_schema新增了几张视图,可以用于各个维度查看内存的使用情况,还有就是这个几个视图的信息还可以在sys这个库中查看:
root@mysqldb 11:18: [performance_schema]> 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)
root@mysqldb 14:45: [performance_schema]>
从表的名字大致就可以看出,就是根据主机,进程,用户,全局等维度对内存进行监控。同时sys也针对这些表的格式做了进一步的优化,使得我们可以很方便的查看。
需要注意的一点就是部分内存维度的监控默认是关闭的,并不是所有的内存监控维度是开启的,还需要自己手动开启这些监控信息:
root@mysqldb 14:51: [performance_schema]> update setup_instruments set enabled='yes' where name like 'memory%';
还有就是这些监控的信息只是会从当前使用的情况开始进行监控的,之前的内存使用情况是无法获取得到的。
- 查看全局内存使用情况:
root@mysqldb 14:57: [performance_schema]> select event_name,SUM_NUMBER_OF_BYTES_ALLOC from memory_summary_global_by_event_name order by SUM_NUMBER_OF_BYTES_ALLOC desc LIMIT 10;
+------------------------------------------------------------------------------+---------------------------+
| event_name | SUM_NUMBER_OF_BYTES_ALLOC |
+------------------------------------------------------------------------------+---------------------------+
| memory/performance_schema/events_statements_history_long | 14320000 |
| memory/performance_schema/events_statements_summary_by_digest.tokens | 10240000 |
| memory/performance_schema/events_statements_history_long.tokens | 10240000 |
| memory/performance_schema/events_statements_history_long.sqltext | 10240000 |
| memory/performance_schema/table_handles | 9502720 |
| memory/performance_schema/events_statements_summary_by_thread_by_event_name | 9091072 |
| memory/performance_schema/memory_summary_by_thread_by_event_name | 5898240 |
| memory/performance_schema/events_statements_summary_by_digest | 5120000 |
| memory/performance_schema/events_statements_summary_by_host_by_event_name | 4545536 |
| memory/performance_schema/events_statements_summary_by_account_by_event_name | 4545536 |
+------------------------------------------------------------------------------+---------------------------+
10 rows in set (0.01 sec)
- 查看进程内存使用情况:
root@mysqldb 14:58: [performance_schema]> select event_name, SUM_NUMBER_OF_BYTES_ALLOC from memory_summary_by_thread_by_event_name order by SUM_NUMBER_OF_BYTES_ALLOC desc limit 20;
+----------------------------------------------+---------------------------+
| event_name | SUM_NUMBER_OF_BYTES_ALLOC |
+----------------------------------------------+---------------------------+
| memory/sql/Relay_log_info::mts_coor | 0 |
| memory/sql/QUICK_RANGE_SELECT::alloc | 0 |
| memory/sql/table_mapping::m_mem_root | 0 |
| memory/sql/sp_head::call_mem_root | 0 |
| memory/sql/sp_head::execute_mem_root | 0 |
| memory/sql/sp_head::main_mem_root | 0 |
| memory/sql/THD::sp_cache | 0 |
| memory/sql/Warning_info::m_warn_root | 0 |
| memory/sql/Protocol_local::m_rset_root | 0 |
| memory/sql/Prepared_statement::main_mem_root | 0 |
| memory/sql/Prepared_statement_map | 0 |
| memory/sql/servers | 0 |
| memory/sql/Table_triggers_list | 0 |
| memory/sql/gdl | 0 |
| memory/sql/new_frm_mem | 0 |
| memory/sql/help | 0 |
| memory/sql/thd::main_mem_root | 0 |
| memory/sql/Delegate::memroot | 0 |
| memory/sql/THD::transactions::mem_root | 0 |
| memory/sql/display_table_locks | 0 |
+----------------------------------------------+---------------------------+
20 rows in set (0.01 sec)
这个时候我们可以根据这些进程名去google或者其他的搜索引擎去获取得到这些相关的信息,这个时候就可以比较很明确的根据具体的情况在进行优化和调整。
NUMA也有可能导致内存泄露
- 什么是NUMA
- 可以移步到:http://cenalulu.github.io/linux/numa/
- NUMA是为了解决SMP系统进程增长导致进程竞用和横向扩展槽糕的问题,它会将CPU平均划分成若干个Chip(最多不超过4个),每个Chip都有自己的内存控制器和内存插槽,但是需要注意的是每个Chip的内存分配并不是均衡的,并且进程在本地的Chip访问本地内存的速度是正常的速度,但是当当前的Chip的内存不足,需要访问远程内存(非本地的Chip)会比原本的慢。
- 查看NUMA的开启情况和内存分配情况
- 我本地的测试是只分配了一个node的。
[root@TiDB-node2 ~]# numactl --show
policy: default
preferred node: current
physcpubind: 0 1 2 3 4 5 6 7
cpubind: 0
nodebind: 0
membind: 0
[root@TiDB-node2 ~]#
[root@TiDB-node2 ~]# numactl --hardware
available: 1 nodes (0)
node 0 cpus: 0 1 2 3 4 5 6 7
node 0 size: 8191 MB
node 0 free: 4093 MB
node distances:
node 0
0: 10
[root@TiDB-node2 ~]#
- 关闭NUMA
- 在BIOS设置层面关闭NUMA,缺点是需要重启OS。
- 或修改GRUB配置文件,缺点也是需要重启OS。
- 升级MySQL版本到5.6.27及以后,新增了一个选项innodb_numa_interleava,只需要重启MySQL实例,无需重启OS。
- MySQL 5.6.27/5.7.9开始引用innodb_numa_interleave选项,但是在5.7.11的Release Notes里提到numa对于online resize buffer pool支持不好,估计是这个原因导致在这之后又临时禁用了,但官方文档里面没有写清楚。不过percona里面一值有这个选项,可以放心使用。
关于MySQL内存泄露的一些BUG
-
同时开启P_S和thread pool会导致内存泄露(percona 5.7.17版本)
- 更早之前官方的5.7.13版本也有发生过这个情况
- 表mysql.gtid_executed的压缩失败导致记录不断的增长,内存不断的增加导致OOM
- MySQL 5.7.17以及之前的版本,当从库设置super_read_only=1的时候,MySQL会认为当前是可读的,应该阻止所有的DML操作,因此GTID合并线程也会失败。
- MySQL 5.8虽然已经修复了这个问题,但是因此导入了新的bug:
The MySQL server is running with the --super-read-only option so it cannot execute this statement
要彻底解决这个问题,务必需要升级到MySQL5.7.19版本。
转载于:https://blog.51cto.com/11819159/2128099
最后
以上就是敏感哈密瓜为你收集整理的【20180611】MySQL OOM的全部内容,希望文章能够帮你解决【20180611】MySQL OOM所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复