想象你经营一家网店,大促瞬间几千个订单同时涌入,如果每单都让客服立刻回电、仓库立刻发货、财务立刻对账,系统当场就会瘫痪。聪明的做法是建一个「订单中转站」:所有请求先扔进去,后端各部门按自己的节奏取走处理。这个中转站,就是消息队列。市面有三款主流中转站,风格迥异:Kafka 像一条超长自动传送带,包裹按到达顺序摊开在带上,极速追加、极速读取,但布局固定不易调整;Pulsar 像一座现代化物流园区,分拣台只管收发,货物统一存入共享总仓,分拣台坏了随时换新,多家公司还能共园而治;RocketMQ 则像同城保价急送,讲究严格先来后到,还支持「货到付款」式的两阶段确认。这篇文章,我们沿着这条物流线,把三者的架构、语义与适用场景一次讲透,帮你选出最匹配的那一款。

岗位关联

选错消息队列如同选错仓库:扩容时翻车、数据错乱时束手无策。搞清 Kafka、Pulsar、RocketMQ 的架构差异,是流式数据工程师做出可靠选型的第一课。

目录
  1. 可视化演示
  2. 消息队列基础
  3. Kafka架构剖析
  4. Pulsar架构剖析
  5. RocketMQ架构剖析
  6. 消息语义对比
  7. 性能生态对比
  8. 选型决策指南
  9. AI 应用场景
  10. Python 演示
  11. 常见误区
  12. 面试题

可视化演示

展示三大消息队列架构差异(Kafka一体/Pulsar分离/RocketMQ事务)、消息投递语义(≤1/≥1/=1)与吞吐/延迟/事务/扩容/生态五维对比,帮助理解MQ选型决策。

本节配有交互动效(进入视口后自动加载,约 3KB)。

'+captions.arch+'

消息队列基础

想象你开了一家网店。大促瞬间涌入几千个订单,如果每一单都让客服立刻打电话、仓库立刻发货、财务立刻对账,系统瞬间就会卡死。聪明的做法是设一个「订单中转站」:下单请求先扔进去,后端各个部门按自己的节奏取走处理。这个中转站,就是消息队列的核心思想——它从不在“谁送”和“谁收”之间强加同步,而是让两边各自为政、异步协作。

对应到技术世界,角色非常清晰:寄件人叫 Producer(生产者),收件人叫 Consumer(消费者),一条专线叫 Topic,中转站里的分拣中心叫 Broker。Producer 只管往 Topic 丢消息,Consumer 按需拉取,二者互不相识。这带来两个杀手级能力:异步解耦——上游不再关心下游是否在线、处理多慢;削峰填谷——流量洪峰先灌进队列,下游按最大处理能力慢慢消化,系统再也不会被瞬时流量冲垮。

但中转站不是无限的,它本质是一个排队系统。排队论里有一条著名定律——利特尔定律(Little's Law):中转站里积压的订单数,等于每秒到达的订单数乘以每个订单平均停留的时间。这条公式,是后面理解三个产品吞吐差异的底层工具。

现在你理解了中转站的价值。但同样是中转站,Kafka、Pulsar、RocketMQ 三家公司的建造方案截然不同:一家铺超长传送带,一家建现代化物流园区,一家做同城保价急送。接下来,我们逐一参观。

L=λ×W\displaystyle L = \lambda \times W
积压量 = 到达速率 × 平均等待时间。中转站越大、处理越快,越不容易爆仓;反之洪峰一来就堆积如山。
  1. L(积压队列长度)中转站里同时滞留的包裹数量,即待处理订单数。
    LL
  2. λ(到达速率)平均每秒涌入中转站的订单数,大促时 λ 会瞬间飙高。
    λ\lambda
  3. W(平均等待时长)每个包裹从进站到被取走的平均时间,下游处理越慢 W 越大。
    WW

Kafka架构剖析

先参观 Kafka。它的仓库是一条超长的自动传送带:所有包裹一到,就按到达顺序一个接一个平铺在传送带上,只能往后追加,绝不允许插队或修改。任何想看包裹的人,只能沿着传送带从头走到尾,按编号(offset)找到自己想要的货。这就是 Kafka 的存储模型——分布式提交日志(distributed commit log)。

传送带太长,一条不够用怎么办?Kafka 把一个 Topic 专线切成多个 Partition(分区),相当于并排铺开多条子传送带。为了防丢失,每条分区的数据会复制 N 份到不同节点(副本)。多分区带来并行度,副本带来可靠性,这是 Kafka 吞吐与容错的两大支柱。

那 Kafka 为什么快?两个秘密:顺序写盘和页缓存。机械硬盘顺序写可达每秒几百 MB,随机写却慢两三个数量级;Kafka 只追加不修改,恰好把磁盘最擅长的顺序写发挥到极致。同时,消息先写操作系统页缓存(page cache),由内核异步刷盘,免去每写一条都等待落盘的延迟。为了保证“副本跟上主节点”,Kafka 维护一个 ISR(In-Sync Replicas)同步副本集合,只有集合内的副本才参与“已确认”判定。

Kafka 把“快”做到了极致,但也有代价:想给传送带换布局很难——加机器要搬数据;想让多个公司共用一条传送带,也缺乏隔离机制。速度之王的短板,正好是下一家 Pulsar 的强项。

QPS≈B×Nt\displaystyle \text{QPS} \approx \frac{B \times N}{t}
吞吐量约等于“每次批量搬运的消息数 × 并行传送带数量 ÷ 单次搬运耗时”。Kafka 的优化,就是把分子做大、把分母做小。
  1. QPS(每秒查询数)传送带系统每秒能处理的请求数,衡量吞吐的核心指标。
    QPS\text{QPS}
  2. B(批大小)Kafka 把多条消息凑成一批再写盘,一次搬运越多效率越高。
    BB
  3. N(分区数)并行子传送带的数量,分区越多并行度越高。
    NN
  4. t(单次耗时)一次批量写入的耗时,顺序写让 t 远小于随机写。
    tt

Pulsar架构剖析

Pulsar 建的是一座现代化物流园区,它与 Kafka 最大的不同可以浓缩成一句话:计算与存储分离。园区里有两类角色:分拣台 Broker 只负责收发包裹、维护会话状态,本身不存任何货;包裹真正存放的地点是共享总仓 BookKeeper,由一批 Bookie 存储节点组成。分拣台坏了,换一台新的立刻上岗,因为货都在总仓里——这就是“Broker 无状态”。

总仓怎么存?Pulsar 把数据切成一个个小段(Segment)分散存到多个 Bookie 上,每段有若干副本。这带来两个好处:分层存储——老数据可以自动滚动到廉价存储,想存多久存多久;扩容像呼吸一样自然——加 Broker 不用搬任何数据,加 Bookie 只是给总仓多几排货架。对比 Kafka 扩容时要把百万级分区搬来搬去,Pulsar 的体验堪称丝滑。

园区由物业统一管理,不同公司可以同时入驻而互不干扰:Pulsar 用 namespace(命名空间)做多租户隔离,每个租户有自己的配额、权限和流量策略。一个租户流量暴涨,最多挤占其所在资源,不会拖垮整座园区。对云厂商和 SaaS 平台来说,这是 Kafka 很难给出的承诺。

园区模式让 Pulsar 在弹性、多租户、长时存储上完胜,但每件货要“分拣台→总仓”两跳,多一次网络往返,裸延迟和吞吐未必比 Kafka 那条直通传送带强。接下来这家,专治“怕乱、怕丢”的场景。

N段=D总量S段\displaystyle N_{\text{段}} = \frac{D_{\text{总量}}}{S_{\text{段}}}
总数据切成多少段存储,取决于总量除以每段大小。段越小,分布越均匀,扩容与老数据迁移越灵活。
  1. N_段(分段数量)总仓里数据被切成多少个小段,决定存储的分散程度。
    N段N_{\text{段}}
  2. D_总量(数据总量)需要存储的全部数据大小,例如 10 TB 的日志。
    D总量D_{\text{总量}}
  3. S_段(每段大小)每个存储段的大小,例如 64 MB。
    S段S_{\text{段}}

RocketMQ架构剖析

RocketMQ 像同城保价急送专线,不追求传送带极速,但把两件事做到极致:严格先来后到,和“货到付款”式的事务保障。为什么需要严格先来后到?银行的转账、电商的下单,消息顺序错了,业务就乱了。RocketMQ 把消息放进有序队列,提供全局顺序和分区顺序两种模式,在金融交易圈口碑极佳。

再看“货到付款”,这是 RocketMQ 的招牌——事务消息。想象你在同城急送下了一单:骑手先取走一个“半包裹”(half message),此时这笔交易处于待定状态,消费者不可见;你确认付款后,系统才把半包裹升级为正式包裹发出。如果中途取消(本地事务回滚),半包裹直接作废。RocketMQ 通过这个两阶段机制,把“发消息”和“本地数据库操作”绑定成同一个事务,杜绝了“订单已付但物流没收到”的惨案。

其他细节同样扎实:主从同步保证高可用;消息带 Tag 支持在 Broker 端过滤,减少无效网络传输;消费失败可按时延不断重投,多次失败最终进入死信队列等人处理。架构上比 Kafka 多了轻量的 NameServer 做路由,运维组件更简单。

保价急送服务周全,但车队规模和速度终究有限:RocketMQ 的吞吐和水平扩展能力不如 Kafka,多租户隔离不如 Pulsar。三家风格已清晰,下一节我们把它们的“承诺”摆到桌面上对比。

P成功=P预提交×P确认\displaystyle P_{\text{成功}} = P_{\text{预提交}} \times P_{\text{确认}}
事务消息整体成功的概率 = 半消息写入成功的概率 × 本地事务确认提交的概率。两步都成,才算成交。
  1. P_成功(整体成功率)一笔事务消息最终被确认提交并送达的概率。
    P成功P_{\text{成功}}
  2. P_预提交(半消息成功率)半包裹成功进入 Broker 的概率,这一步失败则交易直接作废。
    P预提交P_{\text{预提交}}
  3. P_确认(确认提交率)本地业务事务执行成功并确认提交的概率。
    P确认P_{\text{确认}}
  4. ×(乘法关系)两步是“且”的关系,任何一步失败,整体就失败——这就是两阶段的本质。
    ×\times

消息语义对比

快递公司给用户的承诺分等级:Kafka 和 Pulsar 默认是“尽全力投递,可能多送一次”;RocketMQ 事务消息则基本做到“要么确认,要么退货”。这些承诺在消息领域有个名字:投递语义(delivery semantics),分为最多一次、至少一次、恰好一次。传统 MQ 多为“至少一次(at-least-once)”:消息可能重复投递,但绝不丢失,消费者必须自己做到幂等——同一消息处理多次,结果与处理一次相同。

顺序保证是第二个对比维度。Kafka 只在分区内有序,全局分散到多个分区就是乱序;RocketMQ 通过单一队列可做到全局有序,代价是牺牲并行度;Pulsar 的策略与 Kafka 类似,分区内有序。第三个维度是事务能力:RocketMQ 原生事务消息解决“跨系统原子性”;Kafka 的事务(Exactly-once)面向流处理中的原子写,两者不是一回事;Pulsar 的事务支持仍在追赶。

最后是失败处理:三者都会自动重试,多次失败后进入死信队列(DLQ),由人工或旁路任务补偿。别小看语义差异——金融场景里一条消息重复扣款是事故,日志场景里重复一条日志则无伤大雅。这正是选型最容易被忽视、却最影响业务正确性的维度。

承诺等级决定了业务要不要做幂等、要不要写补偿。选快递之前先想清楚:你的业务是丢不起,还是重不得?这个答案,直接指向不同的产品。

E[N]=1+p+p2+⋯=11−p=1q\displaystyle E[N] = 1 + p + p^{2} + \cdots = \frac{1}{1 - p} = \frac{1}{q}
一条消息的期望投递次数满足等比级数:失败概率越高,投递次数越多。至少一次语义的本质,就是用“可能重复”换“绝不丢失”。
  1. E[N](期望投递次数)一条消息最终被投递给消费者的平均次数。
    E[N]E[N]
  2. p(单次失败概率)每次投递失败的几率,网络抖动或节点宕机都会让 p 变大。
    pp
  3. 等比级数求和第 1 次成功,或失败后重试第 2 次成功、第 3 次成功……累加得到 1/(1−p)。
    1+p+p2+⋯1 + p + p^{2} + \cdots
  4. q(成功概率)令 q = 1 − p,q 越小,期望投递次数越大,重复也越严重。
    q=1−pq = 1 - p

性能生态对比

参观完三家仓库,我们再比比车队规模和增值服务。先说吞吐与延迟的体感:单机裸吞吐上,Kafka 凭借顺序写和页缓存通常是第一梯队,尤其适合“写多读少”的日志洪流;RocketMQ 延迟控制出色,适合在线交易链路;Pulsar 因为多了一次存储写入,吞吐下限取决于存储集群,但胜在稳定可预期。

扩容是另一个分水岭。Kafka 加 Broker 时,要把既有分区的数据搬过去(重平衡),数据越多搬得越久,期间消费时延可能抖动;Pulsar 加 Broker 只需告诉园区“新分拣台来了”,数据分毫不动,扩容按秒计算;RocketMQ 的扩容同样需要迁移,但整体设计更轻量,运维门槛低。

多协议与生态方面:Pulsar 原生支持 Kafka 协议、MQTT、AMQP,客户端几乎零改造迁移;Kafka 的杀手锏是生态——Kafka Connect 做数据集成、Schema Registry 管格式、KSQL 做流式查询,加上 Flink/Spark 全家桶的深度适配,流式处理事实标准的地位难以撼动;RocketMQ 生态在国内阿里系技术栈中非常成熟,配套监控告警完善,社区中文资料丰富。

没有一辆车能同时做到最快、最稳、服务最全。性能与生态的取舍,最终要落到业务需求上打分——这就是最后一节要做的事。

T重平衡=D数据V迁移\displaystyle T_{\text{重平衡}} = \frac{D_{\text{数据}}}{V_{\text{迁移}}}
扩容搬数据的时间 = 待迁移数据量 ÷ 迁移速度。数据量越大,扩容阵痛越久,这正是 Kafka 与 Pulsar 体验差距的根源。
  1. T_重平衡(重平衡耗时)新增节点后,数据重新分布所花费的时间。
    T重平衡T_{\text{重平衡}}
  2. D_数据(迁移数据量)需要搬到新节点的数据总量,与集群既有数据规模成正比。
    D数据D_{\text{数据}}
  3. V_迁移(迁移速度)单位时间能搬多少数据,受带宽和磁盘读写限制。
    V迁移V_{\text{迁移}}

选型决策指南

选快递公司,先看你的货是什么。货是海量日志、埋点、指标?Kafka 当仁不让——日志就是纯追加的流,天生匹配 Kafka 的顺序写和重放能力,加上 Flink 生态的深度绑定,实时数据管道的不二之选。这也是 Kafka 吞吐之王的用武之地。

货是订单、转账、库存这类强一致交易?RocketMQ 的事务消息和顺序消息直击痛点,“先半消息、确认后提交”帮你免去手工补偿的深渊。货是“我要给几十个客户开隔离的消息空间”?比如 SaaS 平台、云厂商,Pulsar 的多租户与计算存储分离,让你不必为每个客户单独搭集群,运维成本断崖式下降。

最后还有两个现实因素:成本和团队。小集群、业务简单、团队只熟 Kafka,强行上 Pulsar 的分布式存储反而增加运维负担;反之,规模巨大且多团队共用时,Kafka 的“一人一集群”模式会变成资源黑洞。理性的做法,是把吞吐、事务、多租户、生态、运维五个维度列成评分表,按场景加权求和,让数据替你做决定。

大到国家级快递网络,小到同城跑腿,各有各的适用半径。选型没有最好,只有最匹配——带上这张评分表,你就能从容回答“到底该用哪一个”。

Si=w吞吐×x吞吐,i+w事务×x事务,i+w多租户×x多租户,i\displaystyle S_i = w_{\text{吞吐}} \times x_{\text{吞吐},i} + w_{\text{事务}} \times x_{\text{事务},i} + w_{\text{多租户}} \times x_{\text{多租户},i}
每个候选队列的总分 = 各维度得分乘以权重后求和。权重由业务场景决定:日志场景把“吞吐”权重大幅调高,金融场景把“事务”权重拉满。
  1. S_i(候选队列总分)第 i 个候选消息队列的最终评分。
    SiS_i
  2. w_j(维度权重)第 j 个维度的权重,体现业务对吞吐、事务、多租户的重视程度。
    wjw_{j}
  3. x_ij(维度得分)候选 i 在维度 j 上的能力评分,可以来自压测或社区基准。
    xijx_{i j}
  4. Σ(加权求和)把所有维度得分汇总,总分最高者胜出。
    Σ\Sigma

AI 应用场景

场景1:电商大促日志的实时管道(Kafka)

阶段:数据接入与预处理(Data Ingestion)

解决的问题:大促时 Nginx 日志、用户行为埋点每秒产生上亿条记录,直接写数据库会打爆存储;Kafka 像传送带一样把日志按序追加到分布式日志中,Flink 从任意 offset 重放消费,既保证吞吐又支持回溯分析。

具体案例:某电商平台用 90 台 Kafka 支撑双十一峰值每秒 2000 万条日志。数据先入 Kafka,Flink 实时计算 GMV、UV 等指标;离线数仓另起一套消费者,从同一份日志回放训练数据,一套管道两处复用。

场景2:订单与钱包的跨系统事务(RocketMQ)

阶段:事务一致性与状态同步

解决的问题:下单(订单库)与扣款(钱包库)跨两个系统,若先发消息给钱包再写订单,宕机时会出现“单已下、钱没扣”。传统分布式事务框架太重,RocketMQ 事务消息用两阶段,把本地事务和发消息绑定为原子操作。

具体案例:某支付系统在用户付款时,先向 RocketMQ 发送“半消息”,本地扣款事务成功后再确认提交;若本地事务回滚则消息作废,彻底避免重复扣款与漏扣。

场景3:多租户 SaaS 消息平台(Pulsar)

阶段:资源隔离与弹性扩容

解决的问题:SaaS 平台为几十个企业客户提供消息服务,各客户数据量与峰值差异巨大。用 Kafka 要么“一人一集群”成本爆炸,要么共用集群互相干扰;Pulsar 的 namespace 多租户 + 无状态 Broker,让同一个集群内各客户配额隔离、互不感知。

具体案例:某物联网 SaaS 厂商把 30 个客户的设备消息接入同一个 Pulsar 集群,按租户设置配额。某客户设备大规模上报时,只影响其自身 topic,其余 29 个租户零感知;扩容仅需新增 Broker,几分钟完成。

Python 演示

python62 行
# -*- coding: utf-8 -*-"""Queue semantics simulator: replay Kafka/Pulsar/RocketMQ delivery behaviors"""import random  class Queue:    def __init__(self, name, dup_rate, ordered, tx_mode=False):        self.name = name        self.dup_rate = dup_rate        self.ordered = ordered        self.tx_mode = tx_mode        self.sent_list = []        self.received_list = []        self.rollback_count = 0     def send(self, msg_id):        # RocketMQ: a prepared (half) message may be rolled back        if self.tx_mode and random.random() < 0.02:            self.rollback_count += 1            return        self.sent_list.append(msg_id)     def consume(self):        # Kafka/Pulsar keep order inside a partition but lose global order        seq = list(range(len(self.sent_list)))        if not self.ordered:            random.shuffle(seq)        for idx in seq:            msg_id = self.sent_list[idx]            # at-least-once: the same message may be delivered twice            if random.random() < self.dup_rate:                self.received_list.append((msg_id, 2))            self.received_list.append((msg_id, 1))     def run(self, n):        for i in range(n):            self.send(i)        self.consume()        seen = set(m for m, _ in self.received_list)        dup = len(self.received_list) - len(seen)        lost = n - len(seen)        got = [m for m, _ in self.received_list]        ok_order = got == sorted(got)        print("[%s] delivered=%d dup=%d lost=%d ordered=%s" %              (self.name, len(self.received_list), dup, lost, ok_order))  def main():    random.seed(42)    n = 1000    queues = [        Queue("Kafka", 0.03, False),        Queue("Pulsar", 0.03, False),        Queue("RocketMQ", 0.03, True, True),    ]    for q in queues:        q.run(n)    print("RocketMQ half-message rollbacks:", queues[2].rollback_count)  if __name__ == "__main__":    main()
目的:模拟三类队列在“重复投递、全局顺序、事务回滚”三种语义下的行为差异,直观验证选型时的理论判断。
  1. class Queue:用参数化类抽象队列语义:重复率、是否全局有序、是否启用事务两阶段。
  2. if self.tx_mode and random.random() < 0.02:模拟 RocketMQ 半消息被回滚:确认之前断了,这笔交易就作废。
  3. seq = list(range(len(self.sent_list)))构造消费顺序索引,模拟 Broker 决定消息的分发顺序。
  4. if not self.ordered:Kafka/Pulsar 多分区并发消费导致全局乱序,RocketMQ 单队列保持严格先来后到。
  5. self.received_list.append((msg_id, 2))at-least-once 语义下,同一条消息可能被重复投递,副本标记为 2。
  6. seen = set(m for m, _ in self.received_list)幂等去重:消费者拿到重复消息后也只处理一次。
  7. ok_order = got == sorted(got)校验消费顺序是否被打破,输出 True 或 False。
  8. random.seed(42)固定随机种子,让多次运行的对比结果可复现。

常见误区

误区Kafka 和 RocketMQ 一样都是消息队列,把消息发给它,消费者取走不就完了?它跟普通队列没有本质区别。

正解Kafka 本质是「分布式提交日志」:数据只追加、按 offset 读取、可重复消费。就像档案流水线,包裹被取走并不会消失,消费者自己管理读到哪了(offset)。RocketMQ/Pulsar 更接近传统 MQ 的收发语义。理解这一点,才能解释为什么 Kafka 能高吞吐重放,也才能明白它为什么在“队列消费完即删除”的场景里显得别扭。

为何常见:大家都叫“消息队列”,教程和面试也这么称呼,很少有人去深究“日志存储”与“队列”在数据模型上的根本差异。

误区性能不够就加分区,反正分区越多并行度越高,吞吐一定线性往上涨。

正解分区增加会带来文件句柄、内存占用和 Rebalance 耗时的成本;而且 Kafka 的吞吐之本恰恰是“单分区顺序写”,无限增加分区反而会把顺序写变成随机写,拖垮性能。正确做法是根据目标吞吐和客户端并行度估算分区数,例如单分区约 10 MB/s,目标 100 MB/s 就规划 10 个左右的分区,而不是盲目堆。

为何常见:加分区在早期确实能明显提速,“线性直觉”让人误以为可以一直加下去,直到集群被句柄和重平衡压垮。

误区Pulsar 是最新的架构,计算存储分离听起来就高级,吞吐肯定碾压 Kafka。

正解计算存储分离带来的核心价值是弹性、多租户和运维友好,而不是绝对吞吐。Pulsar 写入要走“分拣台→总仓”两跳,多一次网络往返;在小集群、低延迟场景下未必比 Kafka 快。Kafka 的顺序写盘把裸吞吐做到了极致,日志场景仍是王者。选型要看场景匹配,而不是架构新旧。

为何常见:“新架构 = 更快”是厂商宣传最爱的叙事,容易让人忽略架构背后的权衡与代价。

误区下单和发消息不一致?我可以用 Seata 之类的分布式事务框架,消息队列自己的事务能力无所谓。

正解分布式事务框架解决的是跨库原子性,而“本地事务成功后再发消息”这个时序问题,恰恰是消息队列事务消息的专长。RocketMQ 事务消息用半消息 + 本地事务回查,保证“本地操作和发消息要么都成、要么都败”;Kafka 的 Exactly-once 事务则面向流处理中的原子写,语义和应用场景都不同。概念同名但指向不同,选错就要在业务层写大量补偿代码。

为何常见:都叫“事务”却分属不同层次,初学者把流处理事务、分布式事务、事务消息混为一谈,是面试里最常见的翻车点。

面试题

Q1. Kafka 能实现高吞吐的核心机制是什么?

单选题 · easy

  • A.顺序写磁盘加页缓存← 正确答案
  • B.内存消息队列缓存
  • C.多级索引加速查询
  • D.压缩算法实时编码

答案:A。Kafka 的传送带只能往后追加,顺序写盘比随机写快两三个数量级,页缓存又免去频繁刷盘等待,两者共同铸就高吞吐。内存缓存是所有队列的基本功,索引与压缩只是辅助手段,不是核心秘密。

Q2. Pulsar 与 Kafka 最本质的架构差异是什么?

单选题 · mid

  • A.Pulsar 消息默认持久化
  • B.Pulsar 支持多语言客户端
  • C.Pulsar 将计算与存储分离← 正确答案
  • D.Pulsar 使用共享存储介质

答案:C。分拣台只管收发、总仓负责存储,计算与存储分离是 Pulsar 一切特性(无状态 Broker、秒级扩容、多租户)的根基。多语言客户端和消息持久化 Kafka 同样具备,不算本质差异。

Q3. 下列哪种业务场景最适合选择 Kafka?

单选题 · easy

  • A.多租户云平台消息隔离
  • B.金融转账事务强一致
  • C.全局强顺序业务指令
  • D.海量日志采集与分析← 正确答案

答案:D。日志是纯追加流,恰好命中 Kafka 顺序写与重放能力,加上 Flink 生态深度适配,成为实时数据管道标配。金融强一致和全局强顺序是 RocketMQ 的主场,多租户隔离则是 Pulsar 的主场。

Q4. RocketMQ 事务消息中的「半消息」状态表示什么?

单选题 · mid

  • A.已确认但等待消费者
  • B.已入队且准备投递消费
  • C.已消费但等待回调确认
  • D.已发送但尚未确认执行← 正确答案

答案:D。半消息就像“货到付款”里的预付单,状态待定、消费者暂时不可见;本地事务成功后确认提交,半消息才升级为正式消息。A 描述的是提交后的状态,B 是普通入队状态,C 与半消息无关。

Q5. 关于 at-least-once 投递语义,以下说法正确的是?

单选题 · mid

  • A.消息至少被投递一次← 正确答案
  • B.消息可能完全不被投递
  • C.消息最多被投递一次
  • D.消息恰好被投递一次

答案:A。至少一次语义下消息不丢但可能重复,消费者必须做幂等处理。B 是“零次投递”,C 是“至多一次”,D 是“恰好一次”,都不符合 at-least-once 的定义。

Q6. Pulsar 中承担数据持久化存储的组件是哪个?

单选题 · easy

  • A.各分区本地磁盘缓存
  • B.独立的 Zookeeper 集群
  • C.BookKeeper 存储集群← 正确答案
  • D.无状态 Broker 节点

答案:C。Pulsar 的 Broker 无状态,数据统一存放在 BookKeeper 的 Bookie 节点上,相当于物流园区的共享总仓。Zookeeper 只做元数据协调,本地磁盘缓存的说法不成立。

Q7. 关于 ISR(In-Sync Replicas)机制的作用,正确的是?

单选题 · hard

  • A.压缩消息以降低存储开销
  • B.维护与主副本同步的副本集合← 正确答案
  • C.将消息均匀分配到各分区
  • D.保证所有副本数据强一致

答案:B。ISR 是“跟得上进度的副本清单”,只有清单内的副本才参与 acks 判定,落后太多会被踢出、追上了再拉回来。它保证的是“大多数副本已同步”,并非所有副本强一致,也从不负责压缩和分区分配。

Q8. Pulsar 相比 Kafka 的典型优势有哪些?

多选题 · mid

  • A.Broker 无状态弹性扩容← 正确答案
  • B.存储计算分离分层架构← 正确答案
  • C.支持多租户命名空间隔离← 正确答案
  • D.单分区顺序读写最优性能

答案:ABC。无状态 Broker 让扩容秒级完成,计算存储分离是架构基石,namespace 多租户解决共用集群的隔离问题,三者都是 Pulsar 的招牌。单分区顺序读写最优性能其实是 Kafka 的强项,Pulsar 多一跳存储未必更快。

Q9. 以下属于 RocketMQ 特色能力的有哪些?

多选题 · hard

  • A.事务消息两阶段确认← 正确答案
  • B.全局与分区顺序消息← 正确答案
  • C.消息标签过滤机制← 正确答案
  • D.计算存储分离架构

答案:ABC。事务消息两阶段确认、全局与分区顺序消息、Tag 标签过滤,都是 RocketMQ 的差异化能力。计算存储分离是 Pulsar 的架构特征,不属于 RocketMQ。

Q10. 以下属于 Kafka 生态组件的有哪些?

多选题 · hard

  • A.Kafka Connect 数据集成← 正确答案
  • B.Schema Registry 管理← 正确答案
  • C.KSQL 流式查询引擎← 正确答案
  • D.天然支持多租户强隔离

答案:ABC。Kafka Connect 做数据管道集成,Schema Registry 统一消息格式,KSQL 提供流式 SQL 查询,共同构成 Kafka 的生态护城河。多租户强隔离恰是 Kafka 的短板,并非其生态组件。