百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术教程 > 正文

故障分析 | 一条du命令引发的内存不足报警

mhr18 2025-02-06 15:46 20 浏览 0 评论

作者:任坤

现居珠海,先后担任专职 Oracle 和 MySQL DBA,现在主要负责 MySQL、mongoDB 和 Redis 维护工作。

本文来源:原创投稿

*爱可生开源社区出品,原创内容未经授权不得随意使用,转载请联系小编并注明来源。


1、背景

上班时间收到一条磁盘空间报警

登录该机器查看,根分区只有不到16G,此刻已经使用超过了80%。

查看根分区下最大的10个文件并按照size降序排列

du ‐Sm / ‐‐exclude="/data" | sort ‐k1nr | head ‐10

这条命令在其他环境执行几秒钟就返回了,在这个机器上执行了将近1分钟,最后定位到是几个日志文件,直接删除即可。

刚准备退出登录,又收到一条内存报警,还是这台机器。

2、诊断

查看内存使用情况,确实已经被耗尽

top查看最耗内存的几个进程

消耗内存每多的mysqld只占用了43G,就算加上截图中的其他几个进程,顶多占用44G。 为避免漏算,统计一下所有进程占用的物理内存总和:

[root@centos6564‐220 ~]# more RSS.sh
#/bin/bash
for PROC in `ls /proc/|grep "^[0‐9]"`
do
if [ ‐f /proc/$PROC/statm ]; then
TEP=`cat /proc/$PROC/statm | awk '{print ($2)}'`
RSS=`expr $RSS + $TEP`
fi
done
RSS=`expr $RSS \* 4 / 1024 / 1024`
echo $RSS"GB"

[root@centos6564‐220 ~]# sh RSS.sh
44GB

注:该脚本来自于褚霸多年前的一篇文章 http://blog.yufeng.info/archives/2456

问题来了,剩余的10多G内存被谁占用了? top 和 ps 都给不出答案,只能查看/proc/meminfo文件

注意红框中的信息,slab 消耗了太多的缓存,且都是可回收的,看大小正好有16G左右。

联想到刚刚执行的巨慢的du -Sm命令,答案似乎很明显了。


执行slabtop

dentry 和 inode 占用了很多内存,但是输出结果不够直观。

查看超过100M的 slab 缓存组件

[root@centos6564‐220 ~]# cat /proc/slabinfo |awk '{if($3*$4/1024/1024 > 1
00){print $1,$3*$4/1024/1024 "MB"} }'
xfs_inode 113.586MB
proc_inode_cache 11989.1MB
dentry 3526.19MB

inode 占用了将近12G,dentry 占用了3.5G,一切都对上了。

既然是 slab 缓存导致的内存不足,可以直接用 echo 2 > /proc/sys/vm/drop_caches 命令回收。

至此,内存不足的问题已解决。

3、寻源

新的疑问产生,到底是哪个目录消耗了海量的 inode/dentry?

执行如下命令,统计根目录下每个目录拥有的文件和子目录总数。

for i in `ls / `; do
 count=`ls ‐lR /$i | wc ‐l`
 echo "$i has $count files and dirs"
done
...
proc has 32940780 files and dirs
root has 462 files and dirs
sbin has 287 files and dirs
tmp has 2 files and dirs
....

/proc是元凶,继续探查/proc下的子目录,这次统计细化分为文件和子目录

for i in `ls /proc `; do
 files=`ls ‐lR /proc/$i | grep "^‐" | wc ‐l`
 dirs=`ls ‐lR /proc/$i | grep "^d" | wc ‐l`
 echo "$i has $files files and $dirs dirs" >> /tmp/count_tmps
done
7
#15049进程占用了1600w个文件
[root@centos6564‐220 tmp]# more count_tmps | sort ‐k3nr | head ‐5
15049 has 16381888 files and 964 dirs
 17211 has 7653 files and 349 dirs
 6053 has 7511 files and 384 dirs
 18720 has 2289 files and 269 dirs
 sys has 1166 files and 119 dirs

 [root@centos6564‐220 tmp]# ps ‐ef | grep 15049
 mysql 15049 13839 41 Jan07 ? 85‐09:04:44 /usr/sbin/mysqld ‐‐basedir=/usr
‐‐datadir=/data/var ‐‐plugin‐dir=/usr/lib64/mysql/plugin ‐‐user=mysql ‐‐
log‐error=/data/var/err.log ‐‐pid‐file=/data/var/mysql.pid ‐‐socket=/data/v
ar/mysql.sock ‐‐port=3306
 root 24912 25232 0 01:10 pts/3 00:00:00 grep 15049

多尴尬,查半天居然还是 mysql 的问题。

统计/proc/15049下的子目录信息

dest=/proc/15049
for i in `ls $dest `; do
 files=`ls ‐lR $dest/$i | grep "^‐" | wc ‐l`
 dirs=`ls ‐lR $dest/$i | grep "^d" | wc ‐l`
 echo "$i has $files files and $dirs dirs" >> /tmp/15049
done

[root@centos6564‐220 task]# cat /tmp/15049 | sort ‐k3nr | head ‐5
task has 20428788 files and 955 dirs
 fdinfo has 106921 files and 0 dirs
 net has 60 files and 3 dirs
 attr has 6 files and 0 dirs
 autogroup has 1 files and 0 dirs

/proc/15432/task目录,记录的是 mysqld 衍生的每个子线程的信息。

查看 mysqld 当前的子线程数量

[root@centos6564‐220 task]# cat /proc/15049/status | grep ‐i threads
Threads: 191

继续查看每个子线程具体信息

dest=/proc/15049/task
 for i in `ls $dest `; do
 files=`ls ‐lR $dest/$i | grep "^‐" | wc ‐l`
 dirs=`ls ‐lR $dest/$i | grep "^d" | wc ‐l`
 echo "$i has $files files and $dirs dirs" >> /tmp/15049_task
done

[root@centos6564‐220 tmp]# more 15049_task | sort ‐k3nr | head ‐5
15049 has 106957 files and 4 dirs
 15058 has 106957 files and 4 dirs
 15117 has 106957 files and 4 dirs
 15118 has 106957 files and 4 dirs
 15119 has 106957 files and 4 dirs

每个子线程打开的文件数量是一样的,进入任意1个子线程的 fd 目录,

[root@centos6564‐220 fd]# pwd
/proc/15432/task/15120/fd
[root@centos6564‐220 fd]# ls | wc ‐l
85286

#每一个fd都是1个mysql文件,看命名格式是分区表
[root@centos6564‐220 fd]# ll 39326
lrwx‐‐‐‐‐‐ 1 root root 64 Jul 31 01:34 39326 ‐> /data/tokudb/_*_sql_204d_
542_P_p20161105_188_status_3f14ef598_1_1d.tokudb

4、结论

登录数据库查看 information_schema.partitions ,发现了100多个分区表,每个表1000个分区起步。

这套实例是其他部门半路转交给我们的,该组同学使用 mysql 最大的特点就是喜欢创建分区表。

另外,诊断全程 free -g 显示空闲物理内存为0,但是 mysqld 并没有因此 OOM ,这是因为被额外消耗的那16G内存全属于可回收类型,可以被其他内存请求复用

相关推荐

一文读懂Prometheus架构监控(prometheus监控哪些指标)

介绍Prometheus是一个系统监控和警报工具包。它是用Go编写的,由Soundcloud构建,并于2016年作为继Kubernetes之后的第二个托管项目加入云原生计算基金会(C...

Spring Boot 3.x 新特性详解:从基础到高级实战

1.SpringBoot3.x简介与核心特性1.1SpringBoot3.x新特性概览SpringBoot3.x是建立在SpringFramework6.0基础上的重大版...

「技术分享」猪八戒基于Quartz分布式调度平台实践

点击原文:【技术分享】猪八戒基于Quartz分布式调度平台实践点击关注“八戒技术团队”,阅读更多技术干货1.背景介绍1.1业务场景调度任务是我们日常开发中非常经典的一个场景,我们时常会需要用到一些不...

14. 常用框架与工具(使用的框架)

本章深入解析Go生态中的核心开发框架与工具链,结合性能调优与工程化实践,提供高效开发方案。14.1Web框架(Gin,Echo)14.1.1Gin高性能实践//中间件链优化router:=...

SpringBoot整合MyBatis-Plus:从入门到精通

一、MyBatis-Plus基础介绍1.1MyBatis-Plus核心概念MyBatis-Plus(简称MP)是一个MyBatis的增强工具,在MyBatis的基础上只做增强不做改变,为简化开发、提...

Seata源码—5.全局事务的创建与返回处理

大纲1.Seata开启分布式事务的流程总结2.Seata生成全局事务ID的雪花算法源码3.生成xid以及对全局事务会话进行持久化的源码4.全局事务会话数据持久化的实现源码5.SeataServer创...

Java开发200+个学习知识路线-史上最全(框架篇)

1.Spring框架深入SpringIOC容器:BeanFactory与ApplicationContextBean生命周期:实例化、属性填充、初始化、销毁依赖注入方式:构造器注入、Setter注...

OpenResty 入门指南:从基础到动态路由实战

一、引言1.1OpenResty简介OpenResty是一款基于Nginx的高性能Web平台,通过集成Lua脚本和丰富的模块,将Nginx从静态反向代理转变为可动态编程的应用平台...

你还在为 Spring Boot3 分布式锁实现发愁?一文教你轻松搞定!

作为互联网大厂后端开发人员,在项目开发过程中,你有没有遇到过这样的问题:多个服务实例同时访问共享资源,导致数据不一致、业务逻辑混乱?没错,这就是分布式环境下常见的并发问题,而分布式锁就是解决这类问题的...

近2万字详解JAVA NIO2文件操作,过瘾

原创:小姐姐味道(微信公众号ID:xjjdog),欢迎分享,转载请保留出处。从classpath中读取过文件的人,都知道需要写一些读取流的方法,很是繁琐。最近使用IDEA在打出.这个符号的时候,一行代...

学习MVC之租房网站(十二)-缓存和静态页面

在上一篇<学习MVC之租房网站(十一)-定时任务和云存储>学习了Quartz的使用、发邮件,并将通过UEditor上传的图片保存到云存储。在项目的最后,再学习优化网站性能的一些技术:缓存和...

Linux系统下运行c++程序(linux怎么运行c++文件)

引言为什么要在Linux下写程序?需要更多关于Linux下c++开发的资料请后台私信【架构】获取分享资料包括:C/C++,Linux,Nginx,ZeroMQ,MySQL,Redis,fastdf...

2022正确的java学习顺序(文末送java福利)

对于刚学习java的人来说,可能最大的问题是不知道学习方向,每天学了什么第二天就忘了,而课堂的讲解也是很片面的。今天我结合我的学习路线为大家讲解下最基础的学习路线,真心希望能帮到迷茫的小伙伴。(有很多...

一个 3 年 Java 程序员 5 家大厂的面试总结(已拿Offer)

前言15年毕业到现在也近三年了,最近面试了阿里集团(菜鸟网络,蚂蚁金服),网易,滴滴,点我达,最终收到点我达,网易offer,蚂蚁金服二面挂掉,菜鸟网络一个月了还在流程中...最终有幸去了网易。但是要...

多商户商城系统开发全流程解析(多商户商城源码免费下载)

在数字化商业浪潮中,多商户商城系统成为众多企业拓展电商业务的关键选择。这类系统允许众多商家在同一平台销售商品,不仅丰富了商品种类,还为消费者带来更多样的购物体验。不过,开发一个多商户商城系统是个复杂的...

取消回复欢迎 发表评论: