Apache Pulsar 是新一代云原生消息队列与流处理平台,采用计算与存储分离的架构,天然支持多租户、跨地域复制和海量 Topic。相比 Kafka 的单层设计,Pulsar 用 BookKeeper 做持久化存储、Broker 无状态转发,既扛得住高吞吐消息队列场景,也能长期保留事件流做回放。本文从单机部署一路讲到订阅模式、多租户隔离与生产落地清单。
在订单、日志、IoT 埋点这类场景里,Pulsar 既能当异步解耦的缓冲区,也能当事件溯源的持久化日志。一个常见的落地形态是:上游服务把领域事件发到 Pulsar,下游的履约、风控、数仓各自用独立订阅消费同一份数据,彼此不耦合,新增消费者也无须改动生产者。
一、为什么需要 Pulsar:消息队列与流平台的合体
传统消息中间件里,Kafka 偏向”日志流”、RabbitMQ 偏向”任务队列”,两者能力边界明显。Pulsar 的出现把两条线合到了一起:同一份数据既能像队列一样被多个消费者组并发消费,也能像事件流一样长期保留、随时回放。它把”服务层(Broker)”和”存储层(BookKeeper)”拆开,Broker 变成无状态路由节点,扩缩容时不需要像 Kafka 那样搬移分区数据,这正是它被称为云原生的根本原因。
二、核心架构:Broker、BookKeeper 与 ZooKeeper 三层
Pulsar 的架构由三部分组成:Broker 负责接收生产者的消息、分发给消费者,本身不存数据;BookKeeper 是一组独立的存储节点(Bookie),消息以 ledger 形式追加写入、多副本持久化;ZooKeeper / 元数据服务 保存 Topic 路由、租户与命名空间等元数据。这种分层让”加 Broker 只扩计算、加 Bookie 只扩存储”成为可能,运维弹性明显优于单层架构。
三、快速起一个集群:用 Docker 跑单机版
学习和验证阶段直接用官方 standalone 镜像最省事,一条 compose 就能把 6650(二进制协议)和 8080(管理 API)两个端口暴露出来:
version: "3.8"
services:
pulsar:
image: apachepulsar/pulsar:3.3.0
command: bin/pulsar standalone
ports:
- "6650:6650" # Pulsar 二进制协议端口
- "8080:8080" # Admin REST API 端口
environment:
- PULSAR_MEM="-Xms512m -Xmx512m"
启动后执行 bin/pulsar-admin brokers list 能看到 standalone 节点即表示集群就绪。生产环境则要把 Broker、BookKeeper、元数据服务拆成独立部署,并配置多副本防止单点。
四、生产消费:用官方客户端收发消息
Pulsar 客户端覆盖 Java、Python、Go、Node 等主流语言,语义高度统一。下面用 Java 客户端演示向一个持久化 Topic 发送消息:
import org.apache.pulsar.client.api.*;
PulsarClient client = PulsarClient.builder()
.serviceUrl("pulsar://localhost:6650")
.build();
Producer<String> producer = client.newProducer(Schema.STRING)
.topic("persistent://my-tenant/my-ns/orders")
.create();
producer.send("order-1001 created");
producer.close();
client.close();
消费者需要指定”订阅名”和”订阅类型”,这是 Pulsar 与 Kafka 消费者组最大的不同——同一个 Topic 下可以并存多种订阅:
Consumer<String> consumer = client.newConsumer(Schema.STRING)
.topic("persistent://my-tenant/my-ns/orders")
.subscriptionName("order-processor")
.subscriptionType(SubscriptionType.Shared)
.subscribe();
Message<String> msg = consumer.receive();
System.out.println("收到: " + msg.getValue());
consumer.acknowledge(msg.getMessageId());
Python 侧同样简洁,适合脚本或数据管道接入:
import pulsar
client = pulsar.Client('pulsar://localhost:6650')
producer = client.create_producer('persistent://my-tenant/my-ns/orders')
producer.send(('order-1002 created').encode('utf-8'))
client.close()
五、四种订阅模式:独占、共享、故障转移、Key_Shared
订阅类型决定了消息如何在消费者之间分配,是设计消费逻辑时最先要拍板的事:
| 订阅模式 | 并发消费 | 消息顺序 | 典型场景 |
|---|---|---|---|
| Exclusive 独占 | 仅 1 个消费者 | 严格有序 | 单实例顺序处理 |
| Failover 故障转移 | 主 1 + 备 N | 分区内有序 | 主备高可用 |
| Shared 共享 | 多消费者轮询 | 不保证顺序 | 任务队列、水平扩展 |
| Key_Shared 按 Key | 多消费者 | 相同 Key 有序 | 按用户/订单分片 |
实际项目里,Shared 适合做削峰填谷的任务队列,Key_Shared 能在多实例并发的同时保证同一业务主键(如订单 ID)的消息落到同一消费者,兼顾吞吐与顺序。想系统对比消息中间件的选型,可以参考本站 Kafka 入门、RabbitMQ 实战 与 NATS 实战。
六、多租户:Tenant、Namespace 与资源隔离
Pulsar 原生把”租户(Tenant)→ 命名空间(Namespace)→ Topic”做成三层,一个集群可以安全地服务多个团队甚至多个客户。用 pulsar-admin 几行命令就能建出隔离单元:
bin/pulsar-admin tenants create shop
bin/pulsar-admin namespaces create shop/order
bin/pulsar-admin topics create-partitioned-topic shop/order/events -p 4
bin/pulsar-admin namespaces set-retention shop/order --size 100M --time 7d
通过 Namespace 级别的策略,可以分别设置 retention(保留时长)、backlog 配额、鉴权和限流,不同租户之间互不干扰。这对 SaaS 厂商或中台团队尤其友好,不用为每个业务单独搭一套集群。
七、与 Kafka 怎么选:一张表说清
| 维度 | Apache Pulsar | Apache Kafka |
|---|---|---|
| 架构 | 计算存储分离(Broker+BookKeeper) | 单层(Broker 自带日志) |
| 扩容 | 加 Broker/Bookie 互不影响 | 扩分区需搬移数据 |
| 多租户 | 原生 Tenant/Namespace | 靠 ACL + 约定 |
| 订阅模型 | 四种,可并存 | 消费组一种 |
| 消息确认 | 单条 ack + 重试/死信 | 按偏移提交 |
| 运维复杂度 | 组件多,初期偏重 | 组件少,生态成熟 |
一句话结论:已有深厚 Kafka 生态、追求极致吞吐且团队熟练,继续 Kafka 更省心;若需要多租户隔离、灵活订阅、存算分离弹性,或想在同一平台同时满足队列与流,Pulsar 更合适。和 Redis Streams 这类轻量方案比,Pulsar 胜在规模与治理能力。
另外要注意团队成熟度:Pulsar 的组件更多,初期运维心智负担比 Kafka 重,建议在真正需要多租户或存算分离弹性时再引入,避免为了用而用。若当前只是简单的异步通知,RabbitMQ 这类更轻量的队列往往更快上手。
八、可靠投递:重试、死信与确认机制
生产环境消费必然遇到偶发失败。Pulsar 支持在 Namespace 或 Topic 维度配置重试队列与死信队列(DLQ),超过最大重试次数后消息自动转入 DLQ 供人工排查,不会阻塞主流程:
bin/pulsar-admin topics set-dead-letter-policy -m 3 -dlq persistent://shop/order/events-dlq persistent://shop/order/events
配合消费端的单条 acknowledge,即使进程崩溃未确认的消息也会被重新投递,从而保证”至少一次”语义。需要精确一次(Exactly-Once)时,可借助 Pulsar 的事务消息能力。
九、生产落地检查清单
| 检查项 | 建议做法 |
|---|---|
| 部署形态 | 生产用独立 Broker + BookKeeper + 元数据服务,禁用 standalone |
| 副本与 ack | BookKeeper ensemble 写 3 副本,生产者用 WaitForAll 级确认 |
| 订阅类型 | 按业务选 Shared/Key_Shared,避免误用独占导致堆积 |
| 死信与重试 | 务必配置 DLQ,失败消息隔离不堵主链路 |
| 监控 | 接入 Prometheus 看吞吐、积压、存储延迟 |
| 容量 | 合理设置 retention 与 backlog 配额,防磁盘打满 |
| 发布集成 | 部署与冒烟纳入 GitHub Actions 流水线 |
十、小结
Apache Pulsar 用存算分离的架构把”消息队列”和”事件流”统一到一个平台,原生多租户与四种订阅模式让它在复杂业务里游刃有余。从 Docker 单机起步,到生产环境的副本、死信、监控与 CI 集成,只要按上面的清单逐项落地,就能把这套云原生消息底座真正用稳。当你的消息场景开始要求多团队隔离和弹性扩缩时,Pulsar 会是一个值得长期投入的选择。




