这个场景解决什么
把超过 7 天的日志压成 .gz、超过 90 天的归档删除,是控制日志目录体积最直接的手段。它与 logrotate 是分工关系:logrotate 负责当前日志的切割与轮转,find 与 gzip 负责兜底压缩已经封存的历史文件、并按留存期清理。压缩是 CPU 密集操作,放在低峰执行才不会和业务抢资源。
基本信息
| 场景 | 批量压缩历史日志并清理过期归档 |
|---|---|
| 工具组合 | find 圈定范围、gzip 压缩、xargs 并行、zcat/zgrep 读取 |
| 推荐节奏 | 业务低峰执行,可挂到 cron 或 systemd timer 上 |
| 关键前提 | 只处理已封存的日志,正在写入的当前日志交给 logrotate |
典型使用场景
- 容量治理:日志目录持续增长,靠压缩把近半年的历史文件压到原来的五分之一左右
- 接管现状:目录里已有大量未压缩的旧日志,需要一次性整理成统一形态
- 归档前瘦身:迁移或上传前压缩历史日志,减小传输体积与存储成本
- 替代方案评估:压缩级别、并行度、是否换用 zstd,这些都直接影响耗时与压缩比
- 配合留存策略:压缩与删除分两步走,保留期内可查、保留期外释放空间
压缩与清理
压缩与清理
find /var/log/myapp -type f -name '*.log' -mtime +7 -print | head -20
find /var/log/myapp -type f -name '*.log' -mtime +7 -print0 | xargs -0 -r -P2 -n 20 gzip -9
find /var/log/myapp -type f -name '*.log.gz' -mtime +90 -print0 | xargs -0 -r rm -v --
gzip -l /var/log/myapp/app.log.2026-09-01.gz # 看压缩前后体积与压缩比
zcat -t /var/log/myapp/app.log.2026-09-01.gz # 校验完整性,不解压输出
zgrep -c 'ERROR' /var/log/myapp/app.log.2026-09-01.gz # 压缩状态照样能检索换用 zstd 的现代写法
换用 zstd 的现代写法
# zstd 在压缩比与速度上通常更均衡,且支持多线程
find /var/log/myapp -type f -name '*.log' -mtime +7 -print0 | xargs -0 -r -P2 -n 10 zstd -T2 --rm -q
zstd -t /var/log/myapp/app.log.2026-09-01.zst # 校验
zstdcat /var/log/myapp/app.log.2026-09-01.zst | head # 直接读取常用参数与取舍
| 参数或方案 | 作用 | 取舍 |
|---|---|---|
| gzip -9 | 最高压缩级别 | 耗时最长,日志多为文本,收益通常值得 |
| gzip -k | 保留原文件不删除 | 需要保留原文时用,占用翻倍 |
| gzip -t / gzip -l | 校验完整性 / 查看压缩比 | 批量压完抽查一批即可 |
| xargs -P2 -n 20 | 并行压缩并控制每批参数 | 并行度过高会与业务抢 CPU |
| zstd -T2 --rm | 多线程压缩并删除源文件 | 需目标环境支持解压工具 |
| find --mtime 条件 | 按时间圈定候选 | 注意 mtime 语义,避免误伤当前日志 |
gzip 压缩后会保留原文件的 mtime 与权限,所以后续按时间筛选 .gz 文件时,判断依据仍是原始日志的修改时间,而不是压缩动作发生的时间。这一点对留存策略的设计很关键。
不要压缩正在被进程写入的日志:文件被替换后进程继续写给已删除的 inode,磁盘空间不会释放,日志内容也拿不到。压缩前用 lsof 排查候选文件是否仍被打开。