问题描述
通过WinSCP传输文件给腾讯云的时候,出现了如下的错误:
然后,在微信小程序“腾讯云助手”中发现了此时的一个监控告警:
问题分析
磁盘只读一般的常见原因:
- 磁盘空间满:可以通过df -h命令查看磁盘的使用情况,然后删除多余的文件释放磁盘空间;
- 磁盘inode资源占用完:可以通过df -i命令查看,确认相关的进程;
- 硬件故障:只能问腾讯云的官方客服,让他们的工程师解决了。
磁盘分析
通过之前的常见原因分析,通过命令来进行故障排查:
很明显的:我们可以看到磁盘“/”下的磁盘空间已经满了,占用了整整50G的文件。
这里简单介绍一下df命令:
df命令作用是列出文件系统的整体磁盘空间使用情况。可以用来查看磁盘已被使用多少空间和还剩余多少空间。
df命令显示系统中包含每个文件名参数的磁盘使用情况,如果没有文件名参数,则显示所有当前已挂载文件系统的磁盘空间使用情况。在默认情况下,磁盘空间是以1KB为单位进行显示的,但是,如果POSIXLY_CORRECT环境变量被设置为true,这种情况下默认使用512字节为单位显示。
df命令语法:df [选项] [文件名]
选项 | 含义 |
-a、--all | 显示所有的文件系统,包括虚拟文件系统 |
-B、--block-size | 指定单位大小。比如1k,1m等 |
-h、--human-readable | 以人们易读的GB、MB、KB等格式显示 |
-H | 和-h参数一样,但是不是以1024,而是1000,即1k=1000,而不是1k=1024 |
-i、--inodes | 不用硬盘容量,而是以inode的数量来显示 |
-k | 以KB的容量显示各文件系统,相当于--block-size=1k |
-m | 以MB的容量显示各文件系统,相当于--block-size=1m |
-l、--local | 只显示本地文件系统 |
--no-sync | 在统计使用信息之前不调用sync命令(默认) |
-sync | 在统计使用信息之前调用sync命令 |
-P、--portability | 使用POSIX格式显示 |
-t、--type=TYPE | 只显示指定类型的文件系统 |
-T、--print-type | 显示文件系统类型 |
-x、--exclude-type=TYPE | 不显示指定类型的文件系统 |
--help | 显示帮助信息 |
--version | 显示版本信息 |
例如:
[root@localhost ~]# df /home #指定一个文件夹,查看该文件夹所在磁盘的使用情况
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/sda2 16036224 2749160 12459316 19% /
[root@localhost ~]# df /bin/ls #指定一个文件
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/sda2 16036224 2749160 12459316 19% /
[root@localhost ~]# df /bin/ls /home #指定多个文件或文件夹
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/sda2 16036224 2749160 12459316 19% /
/dev/sda2 16036224 2749160 12459316 19% /
[root@localhost ~]# df /bin/ls /home /usr/ #指定多个文件或文件夹
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/sda2 16036224 2749160 12459316 19% /
/dev/sda2 16036224 2749160 12459316 19% /
/dev/sda2 16036224 2749160 12459316 19% /
[root@localhost ~]# df # 默认情况
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/sda2 16036224 2750464 12458012 19% /
/dev/sda1 295561 16911 263390 7% /boot
tmpfs 1028272 0 1028272 0% /dev/shm
可以看出,df命令是查看磁盘空间使用情况,也就是说,就算指定了某个文件、或者某个文件夹,df命令查看到的依旧是该文件、该文件夹所在的磁盘的空间使用情况。
参考文章: linux命令详解之df命令。
文件夹分析
知道了某个磁盘的使用率为100%,那么怎么查看是因为那个文件夹而导致的磁盘空间满了呢?
这个时候需要使用du命令来查询了:
通过du命令,一直找下去,发现原因是Tomcat的logs日志文件占用了太多的磁盘空间47个G。
这里简单介绍一下du命令:
du命令作用是估计文件系统的磁盘已使用量,常用于查看文件或目录所占磁盘容量。
du命令会直接到文件系统内查找所有文件数据,所以命令执行时会耗费一点儿时间。 在默认情况下,输出结果大小是以KB为单位的。如果想以MB为单位,使用-m参数即可,如果只想知道目录占了多少容量,使用-s参数即可。
du命令语法:du [选项] [文件或目录名称]
选项 | 含义 |
-a:--all | 列出所有的文件和目录容量大小而不仅仅列出目录容量大小,默认情况只是统计目录的容量大小 |
-B:--block-size=SIZE | 指定单位大小 |
-b:--bytes | 以字节为单位列出文件和目录的容量大小 |
-c:--total | 除了列出文件和目录的容量大小外,列出总的容量大小 |
-h:--human-readable | 以人们易读的方式(KB,MB,GB)显示容量大小 |
--si | 和-h参数类似,但是单位换算时是以1000进行换算,而不是1024 |
-k | 和--block-size=1k类似,以KB为单位 |
-m | 和--block-size=1m类似,以MB为单位 |
-s:--summarize | 仅列出总量,而不列出每个目录和文件的大小 |
-S:--separate-dirs | 和-s参数类似,但是统计时不包含子目录的容量大小 |
--max-depth=N | 类似于默认情况的du,但是,递归显示时的递归深度小于等于N。 如果--max-depth=0,就相当于-s参数,只统计总量而已;如果--max-depth=1,就相当于du -s 目录/* |
例如:
[root@localhost test]# du -h /home/test
8.0K /home/test/dir2
12K /home/test/dir1/dir1-dira
876K /home/test/dir1
1.1M /home/test
参考文章:linux命令详解之du命令。
文件分析
确认了某个文件夹的占用了绝大多数的空间,就需要对这个文件夹下的文件进行分析:
通过ls命令,找到这个文件夹下最占磁盘空间的文件——outLog.txt。
问题解决
找到了对应的文件,删除即可:
删除完了之后,我们使用df -h命令继续查看,发现一个奇怪的现象:
也就是说,Linux大文件已删除,但df查看已使用的空间并未减少解决。这个问题的原因是:文件虽然删除了,但是没有释放资源。
一般说来不会出现删除文件后空间不释放的情况,但是也存在例外,比如文件被进程锁定,或者有进程一直在向这个文件写数据等等,要理解这个问题,就需要知道Linux下文件的存储机制和存储结构。
一个文件在文件系统中的存放分为两个部分:数据部分和指针部分,指针位于文件系统的meta-data中,数据被删除后,这个指针就从meta-data中清除了,而数据部分存储在磁盘中,数据对应的指针从meta-data中清除后,文件数据部分占用的空间就可以被覆盖并写入新的内容,之所以出现删除outLog.txt文件后,空间还没释放,就是因为java进程还在一直向这个文件写入内容,导致虽然删除了outLog.txt文件,但文件对应的指针部分由于进程锁定,并未从meta-data中清除,而由于指针并未被删除,那么系统内核就认为文件并未被删除,因此通过df命令查询空间并未释放也就不足为奇了。
既然有了解决问题的思路,那么接下来看看是否有进程一直在向outLog.txt文件中写数据,这里需要用到Linux下的lsof命令,通过这个命令可以获取一个已经被删除但仍然被应用程序占用的文件列表,命令执行如下图所示:
前面很多关于数据库的进程,后面是关于刚刚删除的进程:
从输出结果可以看到,outLog.log文件被进程java锁定,而java进程还一直向这个文件写入日志数据,这个日志文件大小49G.由此可知,这个文件就是导致系统根分区空间耗尽的罪魁祸首,在最后一列的“deleted”状态,说明这个日志文件已经被删除,但由于进程还在一直向此文件写入数据,空间并未释放。
可以直接删除这两个服务:
kill -9 8676
kill -9 17099
但是后果是,这两个服务都被关闭了,需要自己手动重启。
通过ps命令也可以查看进程的情况:
手动重启mysqld和Tomcat服务:
这里也区分一下lsof命令和ps命令:
- lsof命令:用于查看你进程打开的文件,打开文件的进程,进程打开的端口(TCP、UDP);
- ps命令:用于报告当前系统的进程状态。可以搭配kill指令随时中断、删除不必要的程序。
后续
在网上查阅资料的时候,还发现很多人遇到的情况是:df -h显示磁盘占用是没有问题;但是df -i显示磁盘inode资源占用完。
inode译成中文就是索引节点,每个存储设备(例如硬盘)或存储设备的分区被格式化为文件系统后,应该有两部份,一部份是inode,另一部份是Block,Block是用来存储数据用的。而inode呢,就是用来存储这些数据的信息,这些信息包括文件大小、属主、归属的用户组、读写权限等。inode为每个文件进行信息索引,所以就有了inode的数值。操作系统根据指令,能通过inode值最快的找到相对应的文件。
这种情况的原因通常是:尽管那个分区的磁盘占用率未满,但是inode已经用完,应该是该磁盘的某些目录下存在大量的小文件导致。尽管小文件占用的磁盘空间并不大,但是数量太多,inode用尽。
通过ls命令配合wc命令,可以查看某个文件夹下的文件数量。例如:
ls -lt /tmp | wc -l
4011517
wc命令用来计算数字。利用wc指令我们可以计算文件的Byte数(-b)、字数(-w)或是列数(-l)。
至于解决方案,可以参考文章:linux inode已满解决方法。