Pulsar Subscription 模式详解

Pulsar Subscription(订阅) 是消费者消费消息的核心机制,决定了消息如何在多个消费者之间分发。Pulsar 提供了 四种主要的订阅模式(Subscription Types),每种模式适用于不同的业务场景,支持灵活的消息语义(如队列、广播、顺序处理等)。


📘 Pulsar Subscription 模式详解


一、订阅的基本概念

1. 什么是 Subscription?
  • Subscription 是消费者对某个 Topic 的“订阅关系”
  • 每个订阅有一个唯一的名称(如 sub1),并维护一个独立的 消费游标(Cursor),记录当前消费到哪一条消息。
  • 一个 Topic 可以被多个不同的 Subscription 订阅,彼此互不影响(广播语义)。
  • 消费者通过订阅来接收消息。
Topic: orders-topic
 ├─ Subscription: sub-a (Exclusive) → Consumer-A
 ├─ Subscription: sub-b (Shared)     → Consumer-B, Consumer-C
 └─ Subscription: sub-c (Failover)  → Primary: D, Backup: E

💡 游标(Cursor)持久化在 BookKeeper 中,即使消费者重启也能从上次位置继续消费。


二、四种订阅模式详解

Pulsar 支持以下四种核心订阅模式:

模式英文名适用场景
1. 独占模式Exclusive单消费者,高可靠性
2. 共享模式Shared / Round Robin多消费者负载均衡(队列语义)
3. 主备模式Failover消费者主备切换,保证顺序
4. Key 共享模式Key_Shared按消息 Key 分配,保证 Key 级顺序

1. Exclusive(独占模式)

✅ 特点:
  • 只能有一个消费者 订阅该 Subscription。
  • 如果有第二个消费者尝试连接,会收到 SubscriptionBusyException
  • 消息按顺序发送给唯一消费者。
  • 保证 严格的消息顺序恰好一次(Exactly-Once) 语义的可能。
🔧 使用场景:
  • 配置管理、定时任务、日志聚合等需要单一处理者的场景。
🚫 限制:
  • 无法水平扩展消费能力。
  • 单点故障风险。
示例代码(Java):
Consumer<byte[]> consumer = client.newConsumer()
    .topic("orders-topic")
    .subscriptionName("sub-exclusive")
    .subscriptionType(SubscriptionType.Exclusive)
    .subscribe();

2. Shared(共享模式 / 轮询模式)

✅ 特点:
  • 允许多个消费者 同时订阅同一个 Subscription。
  • 消息通过 轮询(Round Robin) 方式分发给消费者,实现负载均衡。
  • 不保证消息顺序(除非单个消费者)。
  • 每个消息只被一个消费者处理(队列语义)。
⚠️ 注意:
  • 消费者可以动态加入或退出。
  • Broker 会根据消费者的接收能力(接收队列大小)进行流量控制。
🔧 使用场景:
  • 高吞吐、可并行处理的业务,如订单处理、图片转码、事件分发。
示例代码(Java):
Consumer<byte[]> consumer = client.newConsumer()
    .topic("orders-topic")
    .subscriptionName("sub-shared")
    .subscriptionType(SubscriptionType.Shared)
    .subscribe();

📌 提示:Shared 模式下,未确认的消息(Unacked)会堆积在 Broker,直到被 Ack 或超时重发。


3. Failover(主备模式 / 故障转移)

✅ 特点:
  • 多个消费者订阅,但 只有一个“主消费者”(Leader) 接收消息。
  • 其他消费者处于“待命”状态。
  • 当主消费者断开时,Broker 自动将下一个消费者提升为新的主消费者。
  • 所有消费者按名字排序,确定主备顺序(字典序)。
🔧 使用场景:
  • 需要 保证消息顺序高可用 的场景,如状态机更新、金融交易回放。
🎯 优势:
  • 既保证顺序性,又具备容错能力。
  • 适合不能并行处理的业务逻辑。
示例代码(Java):
Consumer<byte[]> consumer = client.newConsumer()
    .topic("state-events")
    .subscriptionName("sub-failover")
    .subscriptionType(SubscriptionType.Failover)
    .consumerName("consumer-1")  // 名字决定优先级
    .subscribe();

消费者命名建议:consumer-0, consumer-1, consumer-2,确保排序正确。


4. Key_Shared(Key 共享模式)

✅ 特点:
  • 多个消费者共享订阅。
  • 消息根据 消息 Key(Message Key) 的哈希值分配给特定消费者。
  • 相同 Key 的消息总是由同一个消费者处理,保证 Key 级别的顺序性。
  • 不同 Key 的消息可并行处理,提升吞吐。
🔧 使用场景:
  • 用户行为分析、订单状态更新、会话跟踪等需要“按用户/订单 ID 顺序处理”的场景。
🎯 优势:
  • 兼顾 高吞吐局部顺序性
示例代码(Java):
Producer<byte[]> producer = client.newProducer()
    .topic("user-events")
    .messageRoutingMode(MessageRoutingMode.SinglePartition)
    .hashingScheme(HashingScheme.JavaStringHash)
    .create();

Consumer<byte[]> consumer = client.newConsumer()
    .topic("user-events")
    .subscriptionName("sub-key-shared")
    .subscriptionType(SubscriptionType.Key_Shared)
    .keySharedPolicy(KeySharedPolicy.stickyHash())
    .subscribe();
Key_Shared 策略(Policy):
  • auto_split:自动分裂负载,动态调整 Key 分配。
  • sticky_hash:使用哈希将 Key 分配到消费者,减少重分配。

⚠️ 注意:Producer 必须为每条消息设置 key,否则无法正确路由。

producer.newMessage()
    .key("user-123")  // 必须设置 Key
    .value("clicked")
    .send();

三、订阅模式对比表

模式消费者数量消息顺序吞吐能力容错性典型场景
Exclusive1✅ 全局顺序❌ 低❌ 无单实例任务
SharedN❌ 无序✅ 高✅ 高并行处理队列
FailoverN(主备)✅ 全局顺序⚠️ 中等✅ 高顺序敏感 + HA
Key_SharedN✅ Key 级顺序✅ 高✅ 高分区顺序处理

四、高级订阅功能

1. 共享模式下的 Ack 机制
  • 消费者必须显式调用 acknowledge() 确认消息。
  • 支持批量 Ack、Negative Ack(nack)重试。
consumer.acknowledge(msg);  // 正常确认
consumer.negativeAcknowledge(msg);  // 立即重试
2. 共享模式的 Backlog 控制
  • Broker 为每个消费者维护未确认消息队列。
  • 可设置 receiverQueueSize 控制预取数量,防止消费者过载。
3. 死信队列(DLQ)集成
  • 所有订阅模式都支持配置 DLQ,失败消息自动转入死信 Topic。
pulsar-admin namespaces set-dead-letter-policy my-namespace \
  --maxRedeliverCount 5 \
  --deadLetterTopic my-dlq-topic
4. 重置消费位点(Replay)
  • 可将订阅游标重置到任意时间点,重新消费历史消息。
pulsar-admin topics reset-cursor -s sub1 -t "2024-01-01T00:00:00Z" my-topic

五、最佳实践建议

实践建议
📌 命名规范订阅名应体现用途,如 order-processor, audit-log
📌 避免重复订阅名同一命名空间下不能有两个同名订阅
📌 Shared 模式监控 Backlog关注未确认消息堆积,防止内存溢出
📌 Key_Shared 模式设置 KeyProducer 必须设置 Key,否则路由失效
📌 Failover 模式命名有序使用 consumer-0, consumer-1 确保主备顺序
📌 权限控制通过 Namespace 授权订阅权限

六、可视化示例

Topic: user-actions
│
├── Subscription: sub-batch (Exclusive)
│   └── Batch-Processor (唯一消费者)

├── Subscription: sub-webhook (Shared)
│   ├── Webhook-Sender-1
│   ├── Webhook-Sender-2
│   └── Webhook-Sender-3  → 轮询分发

├── Subscription: sub-recovery (Failover)
│   ├── Primary: Recovery-Service-A
│   └── Backup:  Recovery-Service-B  → 主备切换

└── Subscription: sub-analytics (Key_Shared)
    ├── Analyzer-UserGroup-A  ← Key: user-100, user-101
    ├── Analyzer-UserGroup-B  ← Key: user-200, user-201
    └── Analyzer-UserGroup-C  ← Key: user-300

✅ 总结

订阅模式核心价值
Exclusive简单、顺序、单处理者
Shared高吞吐、负载均衡、队列语义
Failover顺序 + 高可用,主备切换
Key_Shared并行 + Key 级顺序,最灵活

📌 一句话总结

选择正确的订阅模式,是构建高效、可靠消息系统的基石。根据业务是否需要顺序、并发、容错,合理选择 ExclusiveSharedFailoverKey_Shared

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值