通过《Linux文件句柄泄漏》我们已经了解到产生文件句柄泄漏的原因,以及解决方式。今天我们就以一个实例来一步一步演示一下文件句柄泄漏的发现和处理流程。
为了防止因为日志过多导致磁盘爆满而引起进程卡死或宕机,我写了一个Docker磁盘自动清理脚本来实现日志自动清理。但发现其中一台机器始终清理不干净,磁盘占用率始终在85%以上。
1.查看磁盘使用情况
于是,我首先登录到这台机器上查看磁盘的占用情况:
$ df -h
文件系统 容量 已用 可用 已用% 挂载点
/dev/sda2 274G 245G 30G 90% /
devtmpfs 63G 0 63G 0% /dev
tmpfs 63G 12K 63G 1% /dev/shm
......
2.查看子目录磁盘使用情况
然后我用下面的命令查看各子目录所占磁盘的情况:
$ sudo du -h --max-depth=1 /
176M /boot
0 /dev
0 /proc
9.6M /run
0 /sys
30M /etc
1.1M /root
8.0K /tmp
70G /var
3.0G /usr
2.2G /home
0 /media
0 /mnt
292M /opt
0 /srv
76G /
从上面可以看出,各子目录占用磁盘的总量只要76G,而磁盘实际占用已达到245G,那这多出来的169G被谁占用了呢?通过前面的学习,我们大概可以猜出是存在文件句柄泄漏的问题。
3.进程文件句柄数
于是,我再去查看各进程文件句柄的数量:
$ lsof -n|awk '{print $2}'|sort|uniq -c|sort -nr|head -n 10
4956 4110300
312 1341965
296 1980554
276 2318459
268 4109675
268 4109584
240 2275
224 4110005
152 3876624
136 4109612
其中第一列是打开的句柄数,第二列是进程ID。从上面的输出可以看到,4110300号进程所用文件句柄数达到了4956个。从当前的所知的信息来看,很可能就是4110300号进程存在句柄泄漏,但为了防止误判,我们还需要通过下面的命令确认一下:
$ sudo lsof |grep deleted
feature_s 4110300 4111169 root 2w REG 8,2 192867651741 544133607 /home/service/feature_server/log/out.log (deleted)
feature_s 4110300 4111170 root 1w REG 8,2 192867652413 544133607 /home/service/feature_server/log/out.log (deleted)
feature_s 4110300 4111170 root 2w REG 8,2 192867652413 544133607 /home/service/feature_server/log/out.log (deleted)
feature_s 4110300 4111171 root 1w REG 8,2 192867653309 544133607 /home/service/feature_server/log/out.log (deleted)
feature_s 4110300 4111171 root 2w REG 8,2 192867653309 544133607 /home/service/feature_server/log/out.log (deleted)
feature_s 4110300 4111172 root 1w REG 8,2 192867653645 544133607 /home/service/feature_server/log/out.log (deleted)
feature_s 4110300 4111172 root 2w REG 8,2 192867653645 544133607 /home/service/feature_server/log/out.log (deleted)
......
再通过wc -l
统计一下泄漏文件句柄数量:
$ sudo lsof |grep deleted | wc -l
2888
到这里已经确认是4110300号进程导致了句柄泄漏,且泄漏文件句柄数量达到了2888个。
4. kill进程
到这里问题就基本排查清楚了,解决这一类问题的方法有很多种,最简单的方法是关闭或者重启目标进程
kill -9 4110300
当然也可以重启操作系统
sudo reboot
5.如何正确释放磁盘空间?
对于句柄泄漏我们需要kill进程来释放空间,但对应不能重启的进程就无能为力。对待这种进程不停对文件写日志的操作,要释放文件占用的磁盘空间,最好的方法是在线清空这个文件,可以通过如下命令完成:
echo /dev/null > filename
通过这种方法,磁盘空间不但可以马上释放,也可保障进程继续向文件写入日志,这种方法经常用于在线清理Apache、Tomcat、Nginx等Web服务产生的日志文件。
所以,在这里也提醒大家,对于进程正在写入的文件,不要使用rm -f直接删除,而要采取 echo /dev/null > filename 这类将文件置空的方式来释放磁盘空间
。
谢谢阅读,希望能帮到大家。
网友评论