4、日志压缩工具实战:gzip压缩、bzip2压缩、zstd压缩、压缩脚本编写

日志压缩这件事,说实话,我刚开始做运维那会儿根本没当回事。觉得不就是把文件变小嘛,有啥技术含量?直到有一次,线上一个服务疯狂打日志,直接把磁盘写满了,整个集群差点挂了。从那以后,我对压缩工具的选择就格外上心。

今天咱们就聊聊三个主流压缩工具:gzip、bzip2 和 zstd。我会结合实战经验,告诉你什么时候该用谁,怎么用最划算。

4.1 gzip:最通用的老大哥

gzip 应该是大家最熟悉的压缩工具了。Linux 系统基本都自带,兼容性没得说。我个人习惯用它来压缩那些需要长期归档的日志。

基本用法很简单:

# 压缩单个文件
gzip access.log

# 解压缩
gunzip access.log.gz

# 保留原文件压缩
gzip -c access.log > access.log.gz

# 查看压缩率
gzip -l access.log.gz

这里有个坑,我踩过好几次:gzip 默认会删除原文件。如果你只是想压缩一份副本,记得加 -c 参数。

我的经验:gzip 压缩速度不错,压缩率中等。对于文本日志,通常能压到原大小的 10%-20%。适合日常日志轮转场景。

4.2 bzip2:压缩率之王,但慢

bzip2 的压缩率比 gzip 高不少,但代价是速度慢。我记得有一次压一个 10GB 的日志文件,gzip 用了 2 分钟,bzip2 跑了将近 15 分钟。不过压缩后的文件确实小了一圈。

# 压缩
bzip2 error.log

# 解压缩
bunzip2 error.log.bz2

# 保留原文件
bzip2 -k error.log

# 指定压缩级别(1-9,默认9)
bzip2 -9 error.log

你想想看,什么场景下会用 bzip2?我个人建议:那些需要长期保存、不常访问的冷数据。比如一年前的审计日志,用 bzip2 压一下能省不少存储空间。

注意:bzip2 的压缩级别 1-9 对压缩率影响不大,但对速度影响很大。我曾经测试过,级别 1 比级别 9 快 3 倍,但压缩率只差 5% 左右。所以日常用默认级别就行。

4.3 zstd:后起之秀,又快又小

zstd 是 Facebook 开源的压缩算法,这几年在日志领域越来越流行。说实话,我第一次用 zstd 的时候挺震惊的——压缩速度和 gzip 差不多,但压缩率能接近 bzip2。

# 压缩
zstd app.log

# 解压缩
unzstd app.log.zst

# 指定压缩级别(1-19,默认3)
zstd -3 app.log

# 使用多线程(需要编译时支持)
zstd -T4 app.log

为什么会这样?因为 zstd 的算法设计更现代,它可以根据数据特征动态调整策略。我个人现在新上的日志系统,基本都优先考虑 zstd。

性能对比(我实测的数据):
工具 压缩率 压缩速度 解压速度 适用场景
gzip 中等(约 15%) 日常日志轮转
bzip2 高(约 10%) 中等 冷数据归档
zstd 高(约 11%) 实时压缩、传输

4.4 压缩脚本编写实战

光会用命令还不够,咱们得写个脚本把压缩自动化。下面这个脚本是我在项目中实际用过的,经过多次迭代,比较靠谱。

#!/bin/bash
# 日志压缩脚本 - 支持多种压缩算法
# 用法: ./compress_logs.sh /var/log/app

LOG_DIR="$1"
COMPRESS_TOOL="${2:-gzip}"  # 默认用 gzip
RETENTION_DAYS="${3:-7}"    # 保留最近 7 天的日志

# 检查目录是否存在
if [ ! -d "$LOG_DIR" ]; then
    echo "错误:目录 $LOG_DIR 不存在"
    exit 1
fi

# 根据压缩工具选择命令
case "$COMPRESS_TOOL" in
    gzip)
        CMD="gzip"
        EXT=".gz"
        ;;
    bzip2)
        CMD="bzip2"
        EXT=".bz2"
        ;;
    zstd)
        CMD="zstd"
        EXT=".zst"
        ;;
    *)
        echo "不支持的压缩工具: $COMPRESS_TOOL"
        exit 1
        ;;
esac

# 查找需要压缩的日志文件
find "$LOG_DIR" -name "*.log" -type f | while read -r logfile; do
    # 检查文件是否在保留期内
    file_date=$(stat -c %Y "$logfile")
    current_date=$(date +%s)
    age_days=$(( (current_date - file_date) / 86400 ))

    if [ "$age_days" -gt "$RETENTION_DAYS" ]; then
        echo "压缩: $logfile"
        $CMD "$logfile"
        
        if [ $? -eq 0 ]; then
            echo "成功: ${logfile}${EXT}"
        else
            echo "失败: $logfile"
        fi
    fi
done

echo "压缩完成!"

这个脚本有几个设计点我觉得挺实用:

  • 支持三种压缩工具:通过参数切换,不用改脚本
  • 保留期控制:最近几天的日志不压缩,方便排查问题
  • 错误处理:压缩失败不会影响其他文件
避坑指南:我曾经犯过一个错误——在压缩脚本里用了 gzip -9 最高压缩级别。结果日志量大的时候,CPU 被打满,影响了业务。后来改成默认级别,速度提升 3 倍,压缩率只差了 2%。所以别盲目追求最高压缩率。

4.5 如何选择?我的建议

说了这么多,到底该用哪个?我根据实际经验给个参考:

  • 日常日志轮转:用 gzip。兼容性好,速度够快,压缩率也能接受。
  • 远程传输日志:用 zstd。压缩率高、速度快,能节省带宽和时间。
  • 长期冷数据归档:用 bzip2。虽然慢,但存储成本能省不少。
  • 实时流式压缩:用 zstd。它的流式压缩性能最好,延迟低。

嗯,压缩工具的选择没有绝对的对错,关键看你的场景。我建议你拿自己的日志数据跑一遍测试,看看哪个最适合你。毕竟实践出真知嘛。