压缩权衡
压缩减少网络传输和磁盘占用,但消耗 CPU。本文讲清压缩算法的选择、端到端压缩的工作方式、以及如何在 CPU 和带宽之间找到平衡。
1. 压缩在哪里发生
txt
Producer 按 batch 压缩 → Broker 校验并存储 → Consumer 解压生产者按 record batch 压缩消息。Broker 收到 batch 后仍需校验 record batch,并在需要时处理或重新压缩其内容。compression.type=producer(默认)时保留生产者原有压缩格式;指定具体算法时,Broker 会按该配置处理写入日志的 batch,压缩格式不匹配时通常需要重新压缩。消费者收到压缩 batch 后再解压。
压缩和解压的 CPU 开销主要由生产者和消费者承担,Broker 的校验与可能的重新压缩也会产生额外 CPU 开销。
2. 算法对比
压缩比高度依赖数据特征。下表为典型文本或日志类数据的粗略经验范围,仅用于快速建立预期,不是通用性能指标,实际选型应以基准测试为准。
| 算法 | 压缩比 | 压缩速度 | 解压速度 | CPU 开销 | 适用场景 |
|---|---|---|---|---|---|
| none | 1:1 | - | - | 无 | 低延迟场景 |
| gzip | 1:3~1:10 | 慢 | 慢 | 高 | 存储敏感,低吞吐 |
| snappy | 1:2~1:5 | 快 | 快 | 低 | 通用场景 |
| lz4 | 1:2~1:5 | 极快 | 极快 | 低 | 高吞吐场景 |
| zstd | 1:3~1:8 | 中 | 快 | 中 | Kafka 2.1+,平衡场景 |
zstd 支持压缩级别,级别越高通常倾向于更高压缩率,同时 CPU 成本上升;具体收益取决于数据,选型时需连同级别一起评估。
3. 怎么选
| 场景 | 推荐 | 理由 |
|---|---|---|
| 高吞吐、CPU 充足 | lz4 | 通常具有较高的压缩、解压吞吐 |
| 带宽敏感、CPU 充足 | zstd | 通常能以较高 CPU 成本换取更高压缩率 |
| CPU 敏感 | none 或 snappy | none 无压缩计算,需压缩时可评估 Snappy |
| 存储敏感、低吞吐 | gzip | 压缩比高,但慢 |
| 不确定 | lz4 | 合理的默认起点,仍需按实际负载验证 |
4. 批量大小影响压缩比
压缩算法通常对更大的数据块效果更好,能利用多条记录之间的冗余。但实际收益取决于数据分布,不能保证批次越大压缩比一定越高。
java
// 大批次 + 压缩 = 通常效果更好(示例值,需按吞吐与延迟目标调整)
props.put("batch.size", 65536); // 64KB,单分区目标缓冲容量
props.put("linger.ms", 50); // 等待更多消息凑批
props.put("compression.type", "lz4");batch.size 是单个分区的目标缓冲容量,并不保证每批都填满;linger.ms 控制等待凑批的时间。低流量或分区较多的场景下批次可能始终较小,调大 batch.size 不会自动带来更高压缩比。具体参数调优见《吞吐调优》。
| 批次大小 | lz4 压缩比(示意数据) |
|---|---|
| 1KB | ~1.5:1 |
| 16KB | ~2.5:1 |
| 64KB | ~3:1 |
以上数值仅用于演示批次大小可能影响压缩率,具体压缩比取决于数据特征,不可直接用于容量估算。
5. 端到端压缩配置
java
// 生产者:压缩消息
props.put("compression.type", "zstd");
props.put("batch.size", 65536);
props.put("linger.ms", 20);
// Broker:默认 compression.type=producer,保留生产者原压缩格式,不重新压缩
// 消费者:不需要额外配置,自动根据消息头解压6. Broker 端压缩 vs 生产者端压缩
| 特性 | 生产者端压缩 | Broker 端压缩 |
|---|---|---|
| 谁承担 CPU | Producer | Broker |
| 网络传输 | 压缩后传输,节省生产者到 Broker 的带宽 | 无法追回生产者已发出的带宽成本 |
| 推荐 | ✅ 生产环境推荐 | 仅用于特殊场景 |
生产者端压缩能节省网络带宽;若 Topic 配置了不同算法,Broker 重新压缩会增加 CPU 开销。Broker 端压缩只在生产者无法压缩时(如旧版本客户端)才考虑。