4、消息队列选型:Kafka vs Pulsar vs Redis Streams
消息队列选型,说白了就是选「轮子」。但每个轮子的脾气不一样,装错了车,跑起来就颠簸。我在做实时指标聚合时,在这上面栽过跟头,也积累了一些经验。今天咱们就聊聊 Kafka、Pulsar 和 Redis Streams 这三兄弟,看看它们到底该怎么选。
4.1 三款消息队列的核心差异
先看一张对比表,心里有个底:
| 特性 | Kafka | Pulsar | Redis Streams |
|---|---|---|---|
| 存储模型 | 分区日志(磁盘) | 分片 + BookKeeper(磁盘) | 内存 + 可选持久化 |
| 延迟(P99) | 5-20ms | 5-15ms | 1-5ms |
| 吞吐量 | 极高(百万级/秒) | 高(百万级/秒) | 中(十万级/秒) |
| ACK 机制 | ISR + 最小同步副本 | BookKeeper 写入确认 | 消费者组确认 |
| 分区数扩展 | 困难(需重平衡) | 灵活(无状态 Broker) | 简单(分片) |
| 运维复杂度 | 中 | 高 | 低 |
嗯,这里要注意。表格只是参考,实际选型要看你的场景。
4.2 Kafka:吞吐量之王,但延迟有代价
Kafka 是我用得最多的消息队列。它的设计哲学很明确:用顺序写磁盘 + 零拷贝,换极致吞吐。我个人习惯在日志采集、大数据管道这类场景首选 Kafka。
但 Kafka 的延迟并不稳定。为什么?因为它的 ACK 机制。
ACK 配置对延迟的影响:
- acks=0:不等待确认,延迟最低(1-3ms),但可能丢数据。
- acks=1:Leader 写入即返回,延迟中等(5-10ms),Leader 宕机可能丢数据。
- acks=all:等待所有 ISR 副本确认,延迟最高(10-20ms),数据最安全。
我在项目中遇到过一个问题:某个实时指标系统要求 P99 延迟低于 10ms,但用了 acks=all 后,延迟飙到 30ms。后来发现是 ISR 副本数设得太多,副本同步成了瓶颈。调成 acks=1 后,延迟降到了 8ms,但丢数据的风险也上来了。说白了,这就是 trade-off。
4.3 Pulsar:计算与存储分离,延迟更可控
Pulsar 的设计更现代。它把 Broker(计算层)和 BookKeeper(存储层)分开,Broker 是无状态的,扩展分区数不需要重平衡。这一点比 Kafka 灵活得多。
Pulsar 的 ACK 机制基于 BookKeeper 的写入确认。它支持三种级别:
- Ensemble Size (E):数据分片数,默认 3。
- Write Quorum (Qw):需要确认的副本数,默认 2。
- Ack Quorum (Qa):确认写入成功的副本数,默认 2。
举个例子:E=3, Qw=2, Qa=2,意味着数据写入 3 个分片,但只需要 2 个分片确认就算成功。这样延迟比 Kafka 的 acks=all 低,但安全性又比 acks=1 高。
我的经验:Pulsar 的延迟抖动比 Kafka 小。在金融级实时指标场景,我建议用 Pulsar。但它的运维成本高,BookKeeper 和 ZooKeeper 都要管,小团队慎入。
4.4 Redis Streams:低延迟首选,但吞吐量有限
Redis Streams 是 Redis 5.0 引入的功能。它基于内存,延迟极低(1-5ms)。如果你对延迟极度敏感,比如毫秒级的实时指标,Redis Streams 是个好选择。
但它的短板也很明显:
- 吞吐量受限于单机内存,一般不超过 10 万条/秒。
- 数据持久化依赖 RDB/AOF,宕机可能丢数据。
- 消费者组功能不如 Kafka/Pulsar 成熟。
我曾经在一个实时风控项目里用过 Redis Streams。延迟确实漂亮,P99 稳定在 3ms 以内。但后来业务量涨到 20 万条/秒,Redis 扛不住了,只能切到 Pulsar。嗯,选型时一定要考虑未来增长。
4.5 分区数与吞吐量的关系
分区数是影响吞吐量的关键参数。但很多人有个误区:分区越多,吞吐量越高。其实不是线性的。
看这张图:
从图上能看出来:分区数从 0 到 20,吞吐量增长很快;但超过 20 后,曲线变平了。为什么?因为 Broker 的 CPU、网络带宽、磁盘 IO 都有上限。分区太多反而会增加管理开销。
避坑指南:我曾经在一个项目里把 Kafka 分区数设到了 100,结果吞吐量没涨,反而因为频繁的 Leader 选举导致延迟飙升。后来调成 20 个分区,性能反而更好了。分区数不是越多越好,建议根据实际流量压测确定。
4.6 ACK 机制对延迟的深层影响
ACK 机制是延迟的「调节阀」。调得太松,数据不安全;调得太紧,延迟受不了。
咱们拆开来看:
- Kafka 的 ISR 机制:Leader 收到数据后,等待 ISR 列表中的副本同步。ISR 越多,延迟越高。我建议把 min.insync.replicas 设为 2,配合 acks=all,既保证安全,延迟也可控。
- Pulsar 的 BookKeeper 确认:Qa 越小,延迟越低。但 Qa 不能小于 Qw,否则数据可能不一致。我一般设 Qw=2, Qa=2,延迟比 Kafka 的 acks=all 低 30% 左右。
- Redis Streams 的确认:消费者处理完消息后,用 XACK 确认。如果消费者挂了,消息会重新投递。延迟最低,但数据可能重复处理。
实战建议:
- 对延迟极度敏感(P99 < 5ms):选 Redis Streams,但要做好数据去重。
- 对延迟中等敏感(P99 < 20ms):选 Pulsar,Qw=2, Qa=2。
- 对吞吐量要求极高(百万级/秒):选 Kafka,acks=1,配合幂等生产者。
4.7 我的选型决策树
最后,分享一个我常用的决策逻辑:
- 先看延迟要求:P99 低于 5ms?直接上 Redis Streams。
- 再看吞吐量:超过 10 万条/秒?Redis Streams 出局,Kafka 或 Pulsar 二选一。
- 再看扩展性:未来分区数可能频繁调整?选 Pulsar,它无状态 Broker 扩展方便。
- 最后看运维能力:团队小、运维弱?选 Kafka,生态成熟,文档多。
你想想看,选型其实就是在延迟、吞吐、安全、运维之间找平衡。没有完美的消息队列,只有最适合你场景的。