Linux 查找大文件、大目录,解决磁盘空间不足的问题

最近阿里云服务器频繁报警,报警原因就是服务器的内存使用率又高达 98%,云盘使用高达 93%。

云盘空间不足,那就删除文件,它相比解决内存不足要简单,今天我们先来解决云盘空间不足的问题。 而解决此问题,无非就是找大文件和大量小文件,比如:

  • 没有按日期存储的日志文件,如果一直不删除该日志文件,那么它会越来越大。
  • 按日期存储的日志文件,没有按日期删除的话,单个文件可能不大,但是大量的单个文件就不小了。

首先需要你熟悉 df、du、find 这几个命令。

df

df(英文全拼:disk free) 命令用于显示目前在 Linux 系统上的文件系统磁盘使用情况统计。

1
2
3
4
5
6
7
8
$ df   
文件系统 1K-块 已用 可用 已用% 挂载点
devtmpfs 1929004 0 1929004 0% /dev
tmpfs 1940088 0 1940088 0% /dev/shm
tmpfs 1940088 197096 1742992 11% /run
tmpfs 1940088 0 1940088 0% /sys/fs/cgroup
/dev/vda1 61795304 54174716 4668356 93% /
tmpfs 388020 0 388020 0% /run/user/1000

一般/dev/vda1为系统盘,像vdb、vdc为数据盘。

-h

我们发现 df 输出的格式没有单位,可读性太低了。使用 -h 参数可解决。
-h 或 –human-readable 以 K,M,G 为单位,提高信息的可读性。

1
2
3
4
5
6
7
8
$ df -h
文件系统 容量 已用 可用 已用% 挂载点
devtmpfs 1.9G 0 1.9G 0% /dev
tmpfs 1.9G 0 1.9G 0% /dev/shm
tmpfs 1.9G 193M 1.7G 11% /run
tmpfs 1.9G 0 1.9G 0% /sys/fs/cgroup
/dev/vda1 59G 52G 4.5G 93% /
tmpfs 379M 0 379M 0% /run/user/1000

du

du (英文全拼:disk usage)命令用于显示目录或文件的大小。

-h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# admin @ Main in ~/.oh-my-zsh/.git on git:master o [22:17:56] 
$ du -h
8.0K ./logs/refs/remotes/origin
12K ./logs/refs/remotes
8.0K ./logs/refs/heads
24K ./logs/refs
32K ./logs
8.0K ./refs/remotes/origin
12K ./refs/remotes
8.0K ./refs/heads
4.0K ./refs/tags
28K ./refs
44K ./hooks
4.0K ./objects/info
1.2M ./objects/pack
1.2M ./objects
4.0K ./branches
8.0K ./info
1.4M .

从输出可以看出du是显示目录和子目录所占用的磁盘空间。

1
2
3
4
$ du -h .oh-my-zsh/.github/
20K .oh-my-zsh/.github/ISSUE_TEMPLATE
8.0K .oh-my-zsh/.github/workflows
44K .oh-my-zsh/.github/

-a

-a, --all 显示所有目录(包括隐藏目录)和文件(包括隐藏文件)大小。

1
2
3
4
5
6
7
8
9
10
11
12
$ du -ha .oh-my-zsh/.github/
4.0K .oh-my-zsh/.github/ISSUE_TEMPLATE/support.md
4.0K .oh-my-zsh/.github/ISSUE_TEMPLATE/config.yml
4.0K .oh-my-zsh/.github/ISSUE_TEMPLATE/feature_request.md
4.0K .oh-my-zsh/.github/ISSUE_TEMPLATE/bug_report.md
20K .oh-my-zsh/.github/ISSUE_TEMPLATE
4.0K .oh-my-zsh/.github/PULL_REQUEST_TEMPLATE.md
4.0K .oh-my-zsh/.github/FUNDING.yml
4.0K .oh-my-zsh/.github/CODEOWNERS
4.0K .oh-my-zsh/.github/workflows/main.yml
8.0K .oh-my-zsh/.github/workflows
44K .oh-my-zsh/.github/

–max-depth=<目录层数>

比如最多显示两层:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ du -h --max-depth=2                 
24K ./logs/refs
32K ./logs
12K ./refs/remotes
8.0K ./refs/heads
4.0K ./refs/tags
28K ./refs
44K ./hooks
4.0K ./objects/info
1.2M ./objects/pack
1.2M ./objects
4.0K ./branches
8.0K ./info
1.4M .

sort

你有没有发现上一条命令文件列表的目录大小并不是按照从大到小或从小到大的排序。
使用sort命令即可排序。
使用|来分隔不同的命令。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ du -h --max-depth=2 | sort 
12K ./refs/remotes
1.2M ./objects
1.2M ./objects/pack
1.4M .
24K ./logs/refs
28K ./refs
32K ./logs
4.0K ./branches
4.0K ./objects/info
4.0K ./refs/tags
44K ./hooks
8.0K ./info
8.0K ./refs/heads

从上图可以看出,只是输入sort是不行的,文件大小并没有排序。
是的,必须加入sort参数才行。
下面说下本文会用到的sort参数:

  • -r(–reverse) 以相反的顺序来排序。
  • -h( –human-numeric-sort):使用易读性数字(例如:2K、1G),默认从小到大排序。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ du -h --max-depth=2 | sort -rh
1.4M .
1.2M ./objects/pack
1.2M ./objects
44K ./hooks
32K ./logs
28K ./refs
24K ./logs/refs
12K ./refs/remotes
8.0K ./refs/heads
8.0K ./info
4.0K ./refs/tags
4.0K ./objects/info
4.0K ./branches

-s

-s或–summarize 仅显示总计。只显示指定目录或当前目录的大小。

1
2
3
# admin @ Main in ~/.oh-my-zsh/.git on git:master o [22:34:51] 
$ du -sh
1.4M .
1
2
$ du -sh ~
918M /home/admin

find

find 用于查找到的子目录和文件全部进行显示(包括隐藏目录和文件)。

1
2
3
4
5
6
7
8
9
10
11
12
$ find ~/.oh-my-zsh/.github/ 
/home/admin/.oh-my-zsh/.github/
/home/admin/.oh-my-zsh/.github/ISSUE_TEMPLATE
/home/admin/.oh-my-zsh/.github/ISSUE_TEMPLATE/support.md
/home/admin/.oh-my-zsh/.github/ISSUE_TEMPLATE/config.yml
/home/admin/.oh-my-zsh/.github/ISSUE_TEMPLATE/feature_request.md
/home/admin/.oh-my-zsh/.github/ISSUE_TEMPLATE/bug_report.md
/home/admin/.oh-my-zsh/.github/PULL_REQUEST_TEMPLATE.md
/home/admin/.oh-my-zsh/.github/FUNDING.yml
/home/admin/.oh-my-zsh/.github/CODEOWNERS
/home/admin/.oh-my-zsh/.github/workflows
/home/admin/.oh-my-zsh/.github/workflows/main.yml

-name

-name 按名称查找当前目录及子目录的目录或文件。

  • 查找当前目录,.可以省略掉;
  • 查找其他目录,将.替换为路径
1
2
3
4
5
6
7
8
9
$ find -name 'pack*'  
./packed-refs
./objects/pack
./objects/pack/pack-ce42a3aed83714e763869bda4d0f5cc5682dfc9a.pack
./objects/pack/pack-ce42a3aed83714e763869bda4d0f5cc5682dfc9a.idx
./objects/pack/pack-fc84bdb90600217e79fb1d4cba8960f01e16687e.idx
./objects/pack/pack-fc84bdb90600217e79fb1d4cba8960f01e16687e.pack
./objects/pack/pack-4b7d6b93ae069ad2020588466c22f0fef836e042.idx
./objects/pack/pack-4b7d6b93ae069ad2020588466c22f0fef836e042.pack

-type

  • -type f:查找普通文件。

    1
    2
    3
    4
    5
    6
    7
    8
    $ find -name '*pack*' -type f  
    ./packed-refs
    ./objects/pack/pack-ce42a3aed83714e763869bda4d0f5cc5682dfc9a.pack
    ./objects/pack/pack-ce42a3aed83714e763869bda4d0f5cc5682dfc9a.idx
    ./objects/pack/pack-fc84bdb90600217e79fb1d4cba8960f01e16687e.idx
    ./objects/pack/pack-fc84bdb90600217e79fb1d4cba8960f01e16687e.pack
    ./objects/pack/pack-4b7d6b93ae069ad2020588466c22f0fef836e042.idx
    ./objects/pack/pack-4b7d6b93ae069ad2020588466c22f0fef836e042.pack
  • -type d:查找目录。

    1
    2
    $ find -name '*pack*' -type d 
    ./objects/pack

-ctime

-ctime n : 在过去n天内被修改过的文件。
将当前目录及其子目录下所有最近 30 天内更新过的文件列出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$ find ~ -ctime -30
/home/admin
/home/admin/.cache/abrt
/home/admin/.cache/abrt/lastnotification
/home/admin/.forever
/home/admin/.forever/z9UI.log
/home/admin/.forever/config.json
/home/admin/.forever/yhZR.log
/home/admin/.forever/ir7-.log
/home/admin/.forever/dQOt.log
/home/admin/.forever/sock
/home/admin/.forever/sock/worker.1669914763128XxW.sock
/home/admin/.forever/pids
/home/admin/.forever/pids/dQOt.pid
/home/admin/.oh-my-zsh/.git
/home/admin/.oh-my-zsh/cache/grep-alias
/home/admin/.oh-my-zsh/cache/.zsh-update
/home/admin/.oh-my-zsh/log

-size

-size:查找指定大小的文件。

  • 查找大于100M的文件:

    1
    2
    $ find ~ -size +80M
    /home/admin/.forever/6n_r.log
  • 查找大于 40M 小于80M 的文件:

    1
    2
    3
    4
    5
    $ find ~ -size +40M -size -80M
    /home/admin/.forever/H2sJ.log
    /home/admin/.forever/iula.log
    /home/admin/.vscode-server/bin/899d46d82c4c95423fb7e10e68eba52050e30ba3/node
    /home/admin/.vscode-server/bin/c3f126316369cd610563c75b1b1725e0679adfb3/node

查找到文件数量

1
2
$ find . -name '*2022-12*' | wc -l 
15

Linux系统中wc(Word Count)命令的功能为统计指定文件中的字节数、字数、行数,并将统计结果显示输出。如果没有给出文件名,则从标准输入读取。

显示文件大小并排序

xargs

xargs(英文全拼: eXtended ARGuments)是给命令传递参数的一个过滤器,也是组合多个命令的一个工具。
xargs 可以将管道或标准输入(stdin)数据转换成命令行参数,也能够从文件的输出中读取数据。

之所以能用到这个命令,关键是由于很多命令不支持|管道来传递参数。

1
2
find -name "*2022-12*" | ls -l #这个命令是错误的
find -name "*2022-12*" | xargs ls -l #这样才是正确的

我想到的第一种方法就是通过下面的命令。

1
find -name "*2022-12*" | xargs du -csh | sort -rh

它在文件或目录没有空格时是正常的,但是文件或目录有空格就有问题了。

因为 xargs 识别字符段的标识是空格或者换行符,所以如果一个文件名里有空格或者换行符,xargs就会把它识别成两个字符串,自然就出错了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# admin @ Main in /ktt/common/apache-tomcat-7.0.62/logs [17:35:02] 
$ tree -C
.
├── 1
│   └── 1txt2022-12\ 2txt\ 3txt.txt
├── 2022-12\ d1
├── catalina.2022-11-25.log
...
├── catalina.out
├── d12020-01\ d2\ d3
├── d12020-01d2\ d3
├── d12020-12d2\ d3
├── d12022-12\ d2\ d3
├── d12022-12d2\ d3
│   └── catalina.out
├── dd2022-12\ 1
├── delete-tomcat-log.sh
...
8 directories, 28 files

# admin @ Main in /ktt/common/apache-tomcat-7.0.62/logs [17:35:08]
$ find -name "*2022-12*" | xargs du -csh | sort -rh
du: 无法访问"./d12022-12": 没有那个文件或目录
du: 无法访问"d2": 没有那个文件或目录
du: 无法访问"d3": 没有那个文件或目录
du: 无法访问"./2022-12": 没有那个文件或目录
du: 无法访问"d1": 没有那个文件或目录
du: 无法访问"./dd2022-12": 没有那个文件或目录
du: 无法访问"./1/1txt2022-12": 没有那个文件或目录
du: 无法访问"2txt": 没有那个文件或目录
du: 无法访问"3txt.txt": 没有那个文件或目录
du: 无法访问"./d12022-12d2": 没有那个文件或目录
du: 无法访问"d3": 没有那个文件或目录
27M 总用量
4.9M ./localhost_access_log.2022-12-05.txt
...
4.0K 1
...

要解决此问题有两种方法:

方法一

-print0 用于 find-0 用于 xargs

find -print0 表示在 find 的每一个结果之后加一个 NULL 字符,而不是默认加一个换行符。find 默认在每一个结果后加一个 ‘\n’,所以输出结果是一行一行的。当使用了 -print0 之后,就变成一行了。

1
2
$ find -name "*2022-12*" -print0                              
./catalina.2022-12-04.log./localhost_access_log.2022-12-09.txt./localhost_access_log.2022-12-03.txt./d12022-12 d2 d3./localhost_access_log.2022-12-04.txt./localhost.2022-12-05.log./2022-12 d1./host-manager.2022-12-05.log./catalina.2022-12-05.log./manager.2022-12-05.log./dd2022-12 1./localhost_access_log.2022-12-02.txt./localhost_access_log.2022-12-06.txt./localhost_access_log.2022-12-05.txt./localhost_access_log.2022-12-07.txt./1/1txt2022-12 2txt 3txt.txt./d12022-12d2 d3./localhost_access_log.2022-12-01.txt./localhost_access_log.2022-12-08.txt%

**xargs -0**表示 xargsNULL 来作为分隔符。这样前后搭配就不会出现空格和换行符的错误了。选择 NULL 做分隔符,是因为一般编程语言把 NULL 作为字符串结束的标志,所以文件名不可能以 NULL 结尾,这样确保万无一失。

1
2
3
4
5
6
7
8
9
10
11
12
$ find -name "*2022-12*" -print0 | xargs -0 du -csh | sort -rh
101M 总用量
35M ./1/1txt2022-12 2txt 3txt.txt
24M ./d12022-12d2 d3
4.9M ./localhost_access_log.2022-12-05.txt
...
4.0K ./dd2022-12 1
4.0K ./d12022-12 d2 d3
4.0K ./catalina.2022-12-13.log
...
4.0K ./2022-12 d1
4.0K ./1/2/03 2022-12 04
方法二

告诉 xargs 精确的分隔符来处理文件名中的空格。

1
2
3
4
5
6
7
8
9
10
11
$ find -name "*2022-12*" | xargs -d '\n' du -sh | sort -rh
35M ./1/1txt2022-12 2txt 3txt.txt
24M ./d12022-12d2 d3
4.9M ./localhost_access_log.2022-12-05.txt
...
4.0K ./dd2022-12 1
4.0K ./d12022-12 d2 d3
4.0K ./catalina.2022-12-13.log
...
4.0K ./2022-12 d1
4.0K ./1/2/03 2022-12 04

-exec

1
2
3
4
5
6
7
8
9
10
11
$ find -name "*2022-12*" -exec du -sh {} \; | sort -rh
35M ./1/1txt2022-12 2txt 3txt.txt
24M ./d12022-12d2 d3
4.9M ./localhost_access_log.2022-12-05.txt
...
4.0K ./dd2022-12 1
4.0K ./d12022-12 d2 d3
4.0K ./catalina.2022-12-13.log
...
4.0K ./2022-12 d1
4.0K ./1/2/03 2022-12 04

显示文件总大小

1
2
$ find . -name '*2022-12*' | xargs du -ch | tail -1    
23M 总用量

查找大文件

例如查找根目录下面大于 300M 的文件,包含文件属性,并且从大到小排序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ sudo find / -type f -size +300M | xargs ls -lhS 
find: ‘/proc/4450/task/4450/fdinfo/6’: 没有那个文件或目录
find: ‘/proc/4450/fdinfo/5’: 没有那个文件或目录
ls: 无法访问/var/lib/docker/devicemapper/devicemapper/metadata: 权限不够
ls: 无法访问/var/lib/docker/devicemapper/devicemapper/data: 权限不够
ls: 无法访问/var/lib/mysql/mysql/general_log.CSV: 权限不够
ls: 无法访问/var/lib/mysql/mysql/slow_log.CSV: 权限不够
ls: 无法访问/var/lib/mysql/mysql/slow_log.CSN: 权限不够
-r-------- 1 root root 128T 12月 13 17:59 /proc/kcore
-rw-rw---- 1 mysql mysql 8.6G 12月 13 17:58 /var/lib/mysql/ibdata1
-rw-r--r-- 1 root root 2.2G 12月 13 17:58 /ktt/common/logs/KTTMsgServer.log
-rw-r----- 1 mongod mongod 687M 12月 13 17:47 /var/log/mongodb/mongod.log
-rw-rw---- 1 mysql mysql 496M 3月 25 2021 /var/lib/mysql/mysql-bin.000005
-rw-r--r-- 1 mongod mongod 375M 12月 5 10:55 /var/lib/mongo/collection-0--6250607335816643619.wt
-rw-r--r-- 1 mongod mongod 330M 12月 13 17:58 /var/lib/mongo/collection-6--61436590258606920.wt

只显示文件大小和文件路径:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ sudo find / -type f -size +300M | xargs du -h | sort -hr
find: ‘/proc/4511/task/4511/fdinfo/6’: 没有那个文件或目录
find: ‘/proc/4511/fdinfo/5’: 没有那个文件或目录
du: 无法访问"/var/lib/docker/devicemapper/devicemapper/metadata": 权限不够
du: 无法访问"/var/lib/docker/devicemapper/devicemapper/data": 权限不够
du: 无法访问"/var/lib/mysql/mysql/general_log.CSV": 权限不够
du: 无法访问"/var/lib/mysql/mysql/slow_log.CSV": 权限不够
du: 无法访问"/var/lib/mysql/mysql/slow_log.CSN": 权限不够
8.6G /var/lib/mysql/ibdata1
2.2G /ktt/common/logs/KTTMsgServer.log
687M /var/log/mongodb/mongod.log
496M /var/lib/mysql/mysql-bin.000005
375M /var/lib/mongo/collection-0--6250607335816643619.wt
331M /var/lib/mongo/collection-6--61436590258606920.wt
0 /proc/kcore

查找大目录

  1. 直接从系统根目录开始查找(操作系统根目录需要 root 权限)。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    $ sudo du -h --max-depth=1 / | sort -hr
    [sudo] admin 的密码:
    du: 无法访问"/proc/16916/task/16916/fd/4": 没有那个文件或目录
    du: 无法访问"/proc/16916/task/16916/fdinfo/4": 没有那个文件或目录
    du: 无法访问"/proc/16916/fd/3": 没有那个文件或目录
    du: 无法访问"/proc/16916/fdinfo/3": 没有那个文件或目录
    52G /
    38G /var
    8.6G /ktt
    4.5G /usr
    918M /home
    406M /root
    185M /run
    108M /boot

    好家伙,var 目录占了 38G。

  2. 先看下 var 目录。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    $ sudo du -ha /var/ | sort -hr | head -20
    38G /var/
    36G /var/lib
    27G /var/lib/mysql
    18G /var/lib/mysql/mysql
    8.7G /var/lib/mysql/mysql/slow_log.CSV
    8.6G /var/lib/mysql/ibdata1
    8.5G /var/lib/mysql/mysql/slow_log.CSN
    7.7G /var/lib/docker
    4.4G /var/lib/docker/volumes
    3.3G /var/lib/docker/devicemapper/devicemapper/data
    3.3G /var/lib/docker/devicemapper/devicemapper
    3.3G /var/lib/docker/devicemapper
    1.6G /var/lib/mongo
    888M /var/log
    686M /var/log/mongodb/mongod.log
    686M /var/log/mongodb
    507M /var/lib/docker/volumes/wekan2_wekan-db/_data
    507M /var/lib/docker/volumes/wekan2_wekan-db
    496M /var/lib/mysql/mysql-bin.000005
    411M /var/cache

    head命令用来来显示列表前几个,默认显示前 10 个,要查看前 20 个,请使用head -20

    从输出列表可以看出 mysql 的 slow_log.CSV、ibdata1、slow_log.CSN 这三个文件就占了 25.8G。然后其他的就是 docker 和 mongo,这些都与数据相关,先不删除。

  3. 再看下 ktt 目录。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    $ sudo du -ha /ktt/ | sort -hr | head -20
    8.6G /ktt/
    6.4G /ktt/common
    3.6G /ktt/common/apache-tomcat-7.0.62
    3.5G /ktt/common/apache-tomcat-7.0.62/logs
    2.8G /ktt/common/apache-tomcat-7.0.62/logs/catalina.out
    2.1G /ktt/common/logs/KTTMsgServer.log
    2.1G /ktt/common/logs
    604M /ktt/common/download
    594M /ktt/NewNS
    593M /ktt/JavaAPI
    326M /ktt/www
    314M /ktt/Ktt Server Arch
    225M /ktt/NewNS/YS-LoraHomeNS
    224M /ktt/NewNS/YS-LoraHomeNS1
    200M /ktt/common/download/node-v4.2.4-linux-x64
    190M /ktt/common/apache-tomcat-7.0.62-test
    186M /ktt/common/download/node-v6.9.2-linux-x64
    183M /ktt/Ktt Server Arch/BaseCloudNode
    161M /ktt/Ktt Server Arch/BaseCloudNode/node_modules
    158M /ktt/YoSmartAPI
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    $ ls -lhS /ktt/common/apache-tomcat-7.0.62/logs/
    总用量 3.5G
    -rw-r--r-- 1 root root 2.8G 12月 3 11:49 catalina.out
    -rw-r--r-- 1 root root 4.6M 4月 30 2022 localhost_access_log.2022-04-30.txt
    -rw-r--r-- 1 root root 4.4M 4月 30 2022 localhost_access_log.2022-04-29.txt
    -rw-r--r-- 1 root root 4.3M 5月 1 2022 localhost_access_log.2022-05-01.txt
    ...
    -rw-r--r-- 1 root root 123 8月 11 09:45 catalina.2022-08-11.log
    -rw-r--r-- 1 root root 123 9月 22 05:27 catalina.2022-09-22.log
    -rw-r--r-- 1 root root 123 11月 23 14:46 catalina.2022-11-23.log
    -rw-r--r-- 1 root root 123 11月 27 15:58 catalina.2022-11-27.log
    ...
    -rw-r--r-- 1 root root 0 4月 26 2022 host-manager.2022-04-26.log
    -rw-r--r-- 1 root root 0 4月 26 2022 manager.2022-04-26.log

清理 Tomcat log

catalina.out

catalina.out 其实是 tomcat 的标准输出(stdout)和标准出错(stderr),这是在 tomcat 的启动脚本里指定的,如果没有修改的话 stdout 和 stderr 会重定向到这里。所以我们在应用里使用 System.out 打印的东西都会到这里来。另外,如果我们在应用里使用其他的日志框架,配置了向 Console 输出的,则也会在这里出现。比如以 logback 为例,如果配置 ch.qos.logback.core.ConsoleAppender 则会输出到 catalina.out 里。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# admin @ Main in ~ [12:46:35] 
$ l /ktt/common/apache-tomcat-7.0.62/logs/catalina.out
-rw-r--r-- 1 root root 2.8G 12月 4 12:46 /ktt/common/apache-tomcat-7.0.62/logs/catalina.out

# admin @ Main in ~ [12:46:45]
$ stat /ktt/common/apache-tomcat-7.0.62/logs/catalina.out
文件:"/ktt/common/apache-tomcat-7.0.62/logs/catalina.out"
大小:2920223345 块:5703600 IO 块:4096 普通文件
设备:fd01h/64769d Inode:1180457 硬链接:1
权限:(0644/-rw-r--r--) Uid:( 0/ root) Gid:( 0/ root)
最近访问:2022-12-04 11:36:34.160445203 +0800
最近更改:2022-12-04 12:46:49.088511568 +0800
最近改动:2022-12-04 12:46:49.088511568 +0800
创建时间:-

# admin @ Main in ~ [12:46:51]
$ sudo debugfs -R 'stat <1180457>' /dev/vda1
[sudo] admin 的密码:
debugfs 1.42.9 (28-Dec-2013)
Inode: 1180457 Type: regular Mode: 0644 Flags: 0x80000
Generation: 3394270750 Version: 0x00000000:00000001
User: 0 Group: 0 Size: 2920223852
File ACL: 0 Directory ACL: 0
Links: 1 Blockcount: 5703600
Fragment: Address: 0 Number: 0 Size: 0
ctime: 0x638c2651:90d3be50 -- Sun Dec 4 12:47:13 2022
atime: 0x638c15c2:2640cc4c -- Sun Dec 4 11:36:34 2022
mtime: 0x638c2651:90d3be50 -- Sun Dec 4 12:47:13 2022
crtime: 0x6267904e:3012c6a8 -- Tue Apr 26 14:25:18 2022
Size of extra inode fields: 28
...

7 个月该文件就增长了 2.8G,运行 5 年将占用 2.8/7125=24G 左右。

随着每天业务的增长,Tomcat 的 catalina.out 日志变得越来越大,占用磁盘空间不说。要查看某个时候的日志的时候,庞大的日志让你顿时无从下手。一般通过 cronlog 切割软件来切割日志,切割后的日志,还可以定期清理掉久远的日志。当然操作也没那么简单,因此不是本篇文章的重点,下面我讲解如何以最简单的方式来清理日志。

catalina.YYYY-MM-DD.log

catalina.{yyyy-MM-dd}.log 是 Tomcat 自己运行的一些日志,主要记录 Tomcat 在启动和暂停时的运行内容。

localhost.YYYY-MM-DD.log

localhost.{yyyy-MM-dd}.log 主要是应用初始化(listener, filter, servlet)未处理的异常最后被 Tomcat 捕获而输出的日志,它也是包含 Tomcat 的启动和暂停时的运行日志,但它没有 catalina.YYYY-MM-DD.log 日志全。

localhost_access_log.YYYY-MM-DD.txt

Tomcat 的请求访问日志,请求的时间,请求的类型,请求的资源和返回的状态码都有记录。配置这个日志非常有必要,可以让我们清楚的看清请求的状况。

删除指定天数前的 log

查看 10 天前的文件大小和总大小:

1
2
3
4
5
6
7
8
9
10
11
12
$ find . -ctime +10 -name '*' | xargs du -ch
...
3.4M ./localhost_access_log.2022-09-22.txt
8.0K ./catalina.2022-09-06.log
4.0K ./catalina.2022-09-22.log
3.2M ./localhost_access_log.2022-07-14.txt
3.1M ./localhost_access_log.2022-07-15.txt
3.1M ./localhost_access_log.2022-10-08.txt
3.3M ./localhost_access_log.2022-07-03.txt
3.1M ./localhost_access_log.2022-07-18.txt
3.2M ./localhost_access_log.2022-11-15.txt
721M 总用量

删除 10 天前的文件:

1
$ find . -ctime +10 -name '*' -print -delete
  • * 指任何类型的文件,当然你也可以指定文件后缀,如 *.txt。
  • -print 打印删除的文件,
  • -delete 目录和文件都会删除。

时间条件:

  • amin n 查找n分钟以前被访问过的所有文件。
  • atime n: 查找n天以前被访问过的所有文件。
  • cmin n: 查找n分钟以前文件状态被修改过的所有文件。
  • ctime n: 查找n天以前文件状态被修改过的所有文件。
  • mmin n: 查找n分钟以前文件内容被修改过的所有文件。
  • mtime n: 查找n天以前文件内容被修改过的所有文件。

清空 catalina.out 文件

为什么不是删除 catalina.out 文件,因为该文件如果正在被 Tomcat 进程操作,导致虽然删除了该文件,但文件对应的指针部分由于进程锁定,并未从 meta-data 中清除,而由于指针并未被删除,那么系统内核就认为文件并未被删除,因此空间不会释放。

Linux 下文件的存储机制和存储结构:

一个文件在文件系统中的存放分为两个部分:数据部分和指针(inode)部分,指针位于文件系统的 meta-data 中,数据被删除后,这个指针就从 meta-data 中清除了,而数据部分存储在磁盘中,数据对应的指针从 meta-data 中清除后,文件数据部分占用的空间就可以被覆盖并写入新的内容,之所以出现删除catalina.out 文件后,空间还没释放,就是因为 tomcat 进程还在一直向这个文件写入内容,导致虽然删除了 catalina.out 文件,但文件对应的指针部分由于进程锁定,并未从 meta-data 中清除,而由于指针并未被删除,那么系统内核就认为文件并未被删除,因此通过df命令查询空间并未释放也就不足为奇了。

清空文件使用如下命令:

1
2
3
4
5
6
7
cat /dev/null > file
#或者
echo > file
#或者
echo ' ' > file
#推荐
echo -n '' > file # -n 不输出换行符。

如果你通过 rm 删除了 catalina.out,但是发现磁盘空间没有释放,那就只能重启 Tomcat 来解决了。

log 定期清理

通过将上面的清理命令编写为一个 Shell 脚本,然后创建一个 crontab 任务,该任务定期执行该 Shell 脚本。即可实现 log 定期清理。

  1. 编写 delete-tomcat-log.sh 脚本。

    delete-tomcat-log.sh
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    #!/bin/bash
    # author gan
    echo "`date` 开始处理 Tomcat log 文件..."

    echo ''
    echo '处理前磁盘空间:'
    df -h

    echo ''
    echo '当前工作目录:'
    pwd
    echo '切换到工作目录到 /ktt/common/apache-tomcat-7.0.62/logs'
    cd /ktt/common/apache-tomcat-7.0.62/logs3
    echo '当前工作目录:'
    pwd

    echo ''
    echo "查看 10 天前的文件大小和总大小:"
    find -ctime +10 | xargs -d '\n' du -csh | sort -rh
    echo "10 天前的文件数量:"
    find . -ctime +10 | wc -l
    echo "删除 10 天前的文件:"
    find . -ctime +10 -print -delete
    echo "查看 10 天前的文件大小和总大小:"
    find -ctime +10 | xargs -d '\n' du -csh | sort -rh

    echo ''
    filename=catalina.out
    echo '清空前 catalina.out 属性:'
    ls -lh $filename
    filesize=`ls -l $filename | awk '{ print $5 }'`
    maxsize=$((200*1024*1024))
    if [ $filesize -gt $maxsize ]
    then
    echo "$filename 文件大小 `expr $filesize / 1024 / 1024`MB 大于 `expr $maxsize / 1024 / 1024`MB,清空该日志。"
    echo "清空 catalina.out ..."
    echo -n '' > ./catalina.out # -n 不输出换行符。
    echo '清空后 catalina.out 属性:'
    ls -lh ./catalina.out
    # mv media.log media"`date +%Y-%m-%d_%H:%M:%S`".log
    else
    echo "$filename 文件大小 `expr $filesize / 1024 / 1024`MB 小于 `expr $maxsize / 1024 / 1024`MB,不清空该日志。"
    fi

    echo ''
    echo '处理后磁盘空间:'
    df -h

    echo ''
    echo "`date` 完成处理 Tomcat log 文件。"
  2. 使脚本具有执行权限。

    1
    chmod +x ./delete-tomcat-log.sh
  3. 进入编辑 crontab 任务列表

    1
    sudo crontab -e
  4. 添加任务。

    1
    0 2 5 * * /ktt/crons/delete-tomcat-log.sh &>> /ktt/crons/delete-tomcat-log.log
    • 0 2 5 * * 指每个月 5 号 2 点 0 分执行任务。
    • & 指将标准输出标准错误输出都重定向到 delete-tomcat-log.log 文件。
    • >覆盖写入到文件。
    • >>追加写入到文件。

参考

Linux 查找大文件、大目录,解决磁盘空间不足的问题

https://ganzhixiong.com/p/5e91df29/

Author

干志雄

Posted on

2022-12-02

Updated on

2022-12-02

Licensed under

Comments