Bcachefs 完全指南 / 第 8 章:压缩策略
第 8 章:压缩策略
用 CPU 换空间,还是用空间换速度?
8.1 压缩概述
8.1.1 为什么需要压缩
压缩的价值:
┌─────────────────────────────────────────────┐
│ 1. 节省存储成本 │
│ SSD 1TB ≈ ¥600 │
│ 压缩比 3:1 → 等效 3TB → 节省 ¥1200 │
├─────────────────────────────────────────────┤
│ 2. 提高 I/O 吞吐 │
│ 压缩 100MB → 读取 33MB → 传输更快 │
│ 变相提高磁盘带宽 │
├─────────────────────────────────────────────┤
│ 3. 减少写放大 (SSD) │
│ 压缩后写入更少数据 → 延长 SSD 寿命 │
└─────────────────────────────────────────────┘
8.1.2 Bcachefs 压缩特性
| 特性 | 说明 |
|---|---|
| 透明压缩 | 应用程序无需感知 |
| 按块压缩 | 独立压缩每个数据块 |
| 算法可选 | lz4 / zstd / gzip |
| 级别可调 | 每个算法支持多个压缩级别 |
| 在线切换 | 可在运行时切换算法 |
| 不可压缩检测 | 自动跳过不可压缩数据 |
8.2 压缩算法详解
8.2.1 LZ4
# 创建使用 LZ4 的文件系统
sudo bcachefs format /dev/sdb --compression=lz4
# LZ4 特点:
# - 极快的压缩/解压速度
# - 中等压缩比
# - 最低 CPU 开销
LZ4 技术指标:
| 指标 | 值 |
|---|---|
| 压缩速度 | ~780 MB/s |
| 解压速度 | ~4000 MB/s |
| 压缩比 | ~2.1:1 (文本) |
| CPU 开销 | 极低 |
| 内存使用 | 64 KB |
适用场景:
- ✅ 实时压缩需求
- ✅ CPU 资源有限
- ✅ 延迟敏感型应用
- ✅ 已部分压缩的数据(视频流)
8.2.2 Zstandard (zstd)
# 创建使用 zstd 的文件系统(推荐)
sudo bcachefs format /dev/sdb --compression=zstd
# 指定压缩级别(1-19,默认 3)
sudo bcachefs format /dev/sdb --compression=zstd --compression_level=3
zstd 技术指标:
| 级别 | 压缩速度 | 解压速度 | 压缩比 | 适用场景 |
|---|---|---|---|---|
| 1 | ~590 MB/s | ~1500 MB/s | ~2.8:1 | 速度优先 |
| 3 (默认) | ~515 MB/s | ~1500 MB/s | ~3.1:1 | 平衡 |
| 6 | ~350 MB/s | ~1500 MB/s | ~3.3:1 | 压缩比优先 |
| 9 | ~200 MB/s | ~1500 MB/s | ~3.5:1 | 高压缩 |
| 19 | ~15 MB/s | ~1500 MB/s | ~3.8:1 | 极限压缩 |
适用场景:
- ✅ 通用场景(推荐)
- ✅ 文本/代码/日志
- ✅ 虚拟机镜像
- ✅ 数据库备份
8.2.3 Gzip
# 创建使用 gzip 的文件系统
sudo bcachefs format /dev/sdb --compression=gzip
# 指定级别(1-9,默认 6)
sudo bcachefs format /dev/sdb --compression=gzip --compression_level=6
gzip 技术指标:
| 级别 | 压缩速度 | 解压速度 | 压缩比 |
|---|---|---|---|
| 1 | ~200 MB/s | ~400 MB/s | ~2.7:1 |
| 6 (默认) | ~38 MB/s | ~400 MB/s | ~3.0:1 |
| 9 | ~12 MB/s | ~400 MB/s | ~3.1:1 |
适用场景:
- ✅ 需要与 gzip 格式兼容
- ⚠️ 性能不如 zstd
8.3 压缩性能测试
8.3.1 测试脚本
#!/bin/bash
# benchmark-compression.sh
set -e
DEVICE="/dev/sdb"
MOUNT="/mnt/test"
TEST_DATA="/tmp/test-data"
# 创建测试数据
echo "创建测试数据..."
mkdir -p "$TEST_DATA"
# 文本数据
for i in $(seq 1 100); do
cat /var/log/syslog > "$TEST_DATA/text_$i.txt" 2>/dev/null || \
echo "This is test data line $i. " > "$TEST_DATA/text_$i.txt"
done
# 二进制数据
dd if=/dev/urandom of="$TEST_DATA/random.bin" bs=1M count=100
echo "测试数据大小: $(du -sh $TEST_DATA | awk '{print $1}')"
echo ""
# 测试不同算法
for algo in none lz4 zstd gzip; do
echo "=== 测试算法: $algo ==="
# 格式化
sudo bcachefs format "$DEVICE" --compression="$algo" --force
# 挂载
sudo mkdir -p "$MOUNT"
sudo mount -t bcachefs "$DEVICE" "$MOUNT"
# 写入测试
echo -n "写入时间: "
time cp -r "$TEST_DATA" "$MOUNT/"
# 读取测试
echo -n "读取时间: "
sync
echo 3 | sudo tee /proc/sys/vm/drop_caches > /dev/null
time cp -r "$MOUNT/test-data" /tmp/read-test
# 空间使用
echo "空间使用:"
sudo bcachefs fs usage "$MOUNT" | grep -E "user:|Size:"
# 清理
sudo umount "$MOUNT"
rm -rf /tmp/read-test
echo ""
done
# 清理测试数据
rm -rf "$TEST_DATA"
echo "=== 测试完成 ==="
8.3.2 典型测试结果
| 算法 | 写入速度 | 读取速度 | 空间占用 | CPU 使用 |
|---|---|---|---|---|
| none | 500 MB/s | 600 MB/s | 10.0 GB | ~5% |
| lz4 | 450 MB/s | 580 MB/s | 5.2 GB | ~10% |
| zstd (3) | 400 MB/s | 550 MB/s | 4.1 GB | ~15% |
| gzip (6) | 150 MB/s | 400 MB/s | 3.9 GB | ~40% |
测试环境: Intel i7-12700K, NVMe SSD, 10GB 混合数据
8.4 压缩调优
8.4.1 选择压缩算法
决策树:
你的数据是什么类型?
│
├── 文本/代码/日志 → zstd (级别 3-6)
│ 压缩比高,性能好
│
├── 虚拟机镜像 → zstd (级别 1-3)
│ 需要平衡压缩比和写入性能
│
├── 视频/音频/已压缩数据 → none
│ 已压缩数据无法进一步压缩
│
├── 数据库 → lz4 或 zstd (级别 1)
│ 需要最低延迟
│
└── 混合数据 → zstd (级别 3)
通用最佳选择
8.4.2 压缩级别调优
# 测试不同级别
for level in 1 3 6 9; do
echo "=== zstd 级别 $level ==="
sudo bcachefs format /dev/sdb --compression=zstd --compression_level=$level
sudo mount -t bcachefs /dev/sdb /mnt/test
# ... 运行基准测试 ...
sudo umount /mnt/test
done
级别选择指南:
| 优先级 | 推荐级别 | 原因 |
|---|---|---|
| 速度优先 | zstd-1 或 lz4 | 最低 CPU 开销 |
| 平衡 | zstd-3 (默认) | 最佳综合表现 |
| 压缩比优先 | zstd-6 或 zstd-9 | 更小的存储占用 |
| 极限压缩 | zstd-19 | CPU 开销很大 |
8.4.3 在线修改压缩设置
# 挂载时指定
sudo mount -t bcachefs -o compress=zstd,compression_level=6 /dev/sdb /mnt/data
# 重新挂载修改
sudo mount -o remount,compress=lz4 /mnt/data
# 关闭压缩
sudo mount -o remount,compress=none /mnt/data
8.4.4 按目录设置压缩
# Bcachefs 支持按目录/文件设置压缩属性
# (需要内核支持)
# 设置目录的压缩属性
sudo bcachefs setattr /mnt/data/documents/ --compression=zstd
sudo bcachefs setattr /mnt/data/videos/ --compression=none
8.5 压缩与加密的交互
8.5.1 压缩和加密的顺序
正确顺序: 先压缩,后加密
┌─────────────┐ ┌─────────────┐ ┌───────────┐
│ 明文数据 │ ──→ │ 压缩 │ ──→ │ 加密 │ ──→ 磁盘
│ 100 MB │ │ zstd → 30MB │ │ AES-256 │ 30 MB
└─────────────┘ └─────────────┘ └───────────┘
错误顺序: 先加密,后压缩
┌─────────────┐ ┌─────────────┐ ┌───────────┐
│ 明文数据 │ ──→ │ 加密 │ ──→ │ 压缩 │ ──→ 磁盘
│ 100 MB │ │ → 100 MB │ │ 无效果 │ 100 MB
└─────────────┘ └─────────────┘ └───────────┘
原因: 加密后的数据看起来像随机数据,无法压缩
8.5.2 配置建议
# Bcachefs 会自动先压缩后加密
# 只需同时指定两个选项
sudo bcachefs format /dev/sdb --compression=zstd --encrypted
# 注意: 如果数据已加密(如 GPG 文件),压缩无效
8.6 压缩监控
8.6.1 查看压缩统计
# 查看文件系统使用情况
sudo bcachefs fs usage /mnt/data
# 输出示例:
# Data:
# user: 45.2 GiB (压缩前约 120.5 GiB)
# 压缩比: ~2.7:1
8.6.2 实时监控
# 监控 I/O 和 CPU
iostat -x 1
top -p $(pgrep bcachefs)
# 查看压缩相关的内核统计
grep -i compress /proc/fs/bcachefs/*/options
8.6.3 评估压缩效果
#!/bin/bash
# eval-compression.sh
MOUNT="/mnt/data"
echo "=== 压缩效果评估 ==="
# 统计文件数量和实际大小
FILES=$(find "$MOUNT" -type f | wc -l)
ACTUAL_SIZE=$(du -sb "$MOUNT" | awk '{print $1}')
APPARENT_SIZE=$(du -sb --apparent-size "$MOUNT" | awk '{print $1}')
echo "文件数量: $FILES"
echo "实际占用: $(numfmt --to=iec $ACTUAL_SIZE)"
echo "逻辑大小: $(numfmt --to=iec $APPARENT_SIZE)"
echo "压缩比: $(echo "scale=2; $APPARENT_SIZE / $ACTUAL_SIZE" | bc):1"
8.7 特定数据类型优化
8.7.1 日志文件
# 日志文件压缩效果极好
# 通常压缩比 5:1 到 10:1
# 推荐: zstd 级别 6-9
sudo bcachefs format /dev/sdb --compression=zstd --compression_level=6
8.7.2 虚拟机镜像
# VM 镜像压缩效果好(大量零块)
# 但需要考虑写入性能
# 推荐: zstd 级别 1-3
sudo bcachefs format /dev/sdb --compression=zstd --compression_level=1
8.7.3 源代码
# 源代码压缩效果很好
# 通常压缩比 3:1 到 5:1
# 推荐: zstd 级别 3-6
sudo bcachefs format /dev/sdb --compression=zstd --compression_level=3
8.7.4 多媒体文件
# 已压缩格式(JPEG/MP4/H.264)无法进一步压缩
# 推荐: 不压缩
sudo bcachefs format /dev/sdb --compression=none
# 或者让 Bcachefs 自动检测(默认行为)
# 当压缩比 < 1.1 时自动跳过
8.7.5 数据库文件
# 数据库文件压缩需谨慎
# 可能影响随机读取性能
# 推荐: lz4 或 zstd 级别 1
sudo bcachefs format /dev/sdb --compression=lz4
8.8 压缩与碎片化
8.8.1 压缩对碎片化的影响
压缩可能导致更多碎片:
无压缩:
文件 A: Block 0, 1, 2, 3 (连续)
文件 B: Block 4, 5, 6, 7 (连续)
有压缩:
文件 A: Block 0, 1 (压缩后变小,不连续)
文件 B: Block 3, 4 (压缩后变小)
Bcachefs 的优化:
- CoW 特性天然减少碎片
- 后台整理会合并碎片
8.8.2 碎片整理
# 触发在线碎片整理
sudo bcachefs fs defrag /mnt/data
# 监控碎片状态
sudo bcachefs fs usage --verbose /mnt/data
8.9 压缩故障排除
8.9.1 压缩比异常低
# 检查数据类型
file /mnt/data/somefile
# 可能原因:
# 1. 数据已压缩(视频、图片、压缩包)
# 2. 数据已加密
# 3. 随机数据
# 解决: 对这类数据关闭压缩
8.9.2 CPU 使用率过高
# 检查压缩算法和级别
mount | grep bcachefs
# 可能原因:
# 1. 使用了高压缩级别(如 zstd-19)
# 2. 大量写入操作
# 解决:
# 1. 降低压缩级别
# 2. 切换到 lz4
# 3. 对部分数据关闭压缩
8.9.3 I/O 性能下降
# 监控压缩相关的 I/O
iostat -x 1
# 可能原因:
# 1. CPU 成为瓶颈(压缩/解压)
# 2. 写放大
# 解决:
# 1. 使用更快的压缩算法
# 2. 升级 CPU
# 3. 考虑关闭压缩
8.10 完整示例
混合数据环境配置
#!/bin/bash
# setup-mixed-compression.sh
DEVICE="/dev/sdb"
MOUNT="/mnt/data"
# 创建文件系统,使用 zstd 默认压缩
sudo bcachefs format "$DEVICE" --compression=zstd --compression_level=3
# 挂载
sudo mkdir -p "$MOUNT"
sudo mount -t bcachefs "$DEVICE" "$MOUNT"
# 创建目录结构
mkdir -p "$MOUNT"/{documents,logs,media,virtual-machines,backups}
# 设置不同目录的压缩策略
# 文档: 高压缩
sudo bcachefs setattr "$MOUNT/documents/" --compression=zstd 2>/dev/null || true
# 日志: 高压缩
sudo bcachefs setattr "$MOUNT/logs/" --compression=zstd 2>/dev/null || true
# 媒体文件: 不压缩
sudo bcachefs setattr "$MOUNT/media/" --compression=none 2>/dev/null || true
# 虚拟机: 快速压缩
sudo bcachefs setattr "$MOUNT/virtual-machines/" --compression=lz4 2>/dev/null || true
echo "=== 配置完成 ==="
echo "目录压缩策略:"
echo " documents/: zstd (高压缩)"
echo " logs/: zstd (高压缩)"
echo " media/: none (不压缩)"
echo " virtual-machines/: lz4 (快速压缩)"
echo " backups/: zstd (默认)"
8.11 本章小结
| 算法 | 压缩比 | 速度 | CPU | 推荐场景 |
|---|---|---|---|---|
| none | 1:1 | 最快 | 无 | 已压缩数据 |
| lz4 | ~2:1 | 极快 | 低 | 实时/数据库 |
| zstd | ~3:1 | 快 | 中 | 通用(推荐) |
| gzip | ~3:1 | 慢 | 高 | 兼容性需求 |
核心决策:
- 大多数场景 → zstd 级别 3
- 性能敏感 → lz4
- 存储敏感 → zstd 级别 6-9
- 已压缩数据 → none
扩展阅读
上一章: ← 第 7 章:快照管理 | 下一章: 第 9 章:性能调优 →