3. 消息队列选型:Kafka vs RabbitMQ vs Pulsar
消息队列选型这事儿,我这些年踩过不少坑。说白了,没有银弹。每个中间件都有自己的脾气,选对了事半功倍,选错了天天加班修数据。
咱们做实时行情数据处理,核心诉求其实就三个:高吞吐、低延迟、不丢数据。嗯,这三个目标有时候是互相矛盾的,得看业务场景做取舍。
3.1 三巨头对比:Kafka、RabbitMQ、Pulsar
先给个直观的对比表,方便你快速建立认知:
| 特性 | Kafka | RabbitMQ | Pulsar |
|---|---|---|---|
| 设计定位 | 分布式日志流 | AMQP消息代理 | 云原生消息流 |
| 吞吐量 | 百万级/秒 | 万级/秒 | 百万级/秒 |
| 延迟 | 毫秒级 | 微秒级 | 毫秒级 |
| 消息顺序 | 分区内有序 | 队列内有序 | 分区内有序 |
| 消息回溯 | 支持(基于offset) | 不支持 | 支持(基于cursor) |
| 运维复杂度 | 中等 | 低 | 高 |
我个人习惯,先看业务场景再选技术。举个例子:
- Kafka:适合做数据管道、日志采集、流式计算。我上一家公司的行情系统,每秒要处理50万笔交易,Kafka扛得住。
- RabbitMQ:适合做任务调度、异步解耦。如果你只是把订单消息从A系统发给B系统,用它最省心。
- Pulsar:适合做多租户、跨地域复制。我记得有个金融客户,要求上海和香港机房数据实时同步,Pulsar的geo-replication天然支持。
我的建议:实时行情系统,首选Kafka。原因有三:
- 行情数据本质是日志流,Kafka的append-only设计完美匹配
- 分区机制天然支持并行消费,吞吐量线性扩展
- 社区生态成熟,Flink、Spark Streaming都原生集成
3.2 Topic与Partition设计
Topic和Partition是Kafka的核心抽象。很多新手上来就建一个Topic,所有数据往里塞,结果性能一塌糊涂。我刚开始也犯过这个错。
Topic设计原则:按业务实体划分。比如行情系统,我一般这样设计:
topic: stock_trade # 股票成交数据
topic: stock_quote # 股票行情快照
topic: stock_order # 委托单数据
topic: market_index # 指数行情
为什么这么分?因为不同数据的消费方不同。成交数据要给风控系统,行情快照要给前端展示,分开后可以独立调整分区数和消费策略。
Partition设计:这是性能的关键。我分享一个经验公式:
分区数 = max(生产者吞吐 / 单分区写入能力, 消费者吞吐 / 单分区消费能力)
举个例子,假设你的行情系统每秒要写入100万条消息,单分区能扛5万条/秒,那至少需要20个分区。但别算得太死,留30%的余量。
避坑指南:分区数不是越多越好。我曾经把一个Topic设了100个分区,结果ZooKeeper的选举压力巨大,集群频繁抖动。一般建议单Topic不超过50个分区,除非你用了Kafka 2.8+的KRaft模式。
分区键的选择也很讲究。行情数据我一般用股票代码做分区键,保证同一只股票的数据落在同一个分区里,这样消费端做聚合计算时不用跨分区拉数据。
3.3 消息可靠性保证
做金融数据的,丢消息就是事故。我见过有人因为没配好ACK机制,丢了半小时的行情数据,最后被客户投诉到CEO那里。
Kafka的消息可靠性,主要靠三个参数控制:
| 参数 | 取值 | 含义 | 可靠性 |
|---|---|---|---|
| acks | 0 | 不等待确认 | 可能丢数据 |
| acks | 1 | Leader确认即可 | Leader宕机可能丢 |
| acks | all | 所有副本确认 | 最高可靠性 |
行情系统我建议用acks=all,配合min.insync.replicas=2。什么意思呢?就是消息必须写入Leader和至少一个Follower才算成功。这样即使Leader挂了,Follower也能顶上。
生产者端还要配重试机制:
# 生产者配置示例
retries = 5
retry.backoff.ms = 100
enable.idempotence = true # 开启幂等性,防止重复
消费者端同样重要。我习惯手动提交offset:
# 消费者配置
enable.auto.commit = false
# 处理完业务逻辑后再手动提交
consumer.commitSync();
注意:手动提交offset时,一定要在业务处理成功之后再提交。我曾经见过一个同事,先提交offset再处理业务,结果处理到一半系统重启了,消息就永远丢了。嗯,血的教训。
3.4 架构图:消息流转全链路
下面这张图,是我根据实际项目经验画的。它展示了行情数据从采集到消费的完整链路:
这张图里,我特意把可靠性保障机制单独标出来了。你看,从数据源到生产者,从生产者到Kafka,再从Kafka到消费者,每个环节都有对应的可靠性策略。少了任何一个环节,都可能出问题。
3.5 选型总结
说了这么多,最后给个结论性的建议:
- 小规模系统(日处理百万级消息):RabbitMQ够用,运维简单,延迟低
- 中等规模系统(日处理亿级消息):Kafka是标配,生态好,坑少
- 大规模系统(日处理百亿级消息):Pulsar值得考虑,但团队要有足够的技术储备
我个人在实时行情项目里,清一色用的Kafka。不是因为它最好,而是因为它最稳。你想想看,金融系统最怕什么?最怕线上出问题没人能修。Kafka的社区活跃度最高,遇到问题StackOverflow上基本都能找到答案。
嗯,消息队列选型这块,今天就聊到这儿。记住一句话:选技术不是选最潮的,而是选你最熟悉的。