Apache Pulsar Consumer(消费者) 是从 Pulsar Topic 接收并处理消息的客户端组件,是消息系统的“出口”。Pulsar 的 Consumer 设计灵活、高效,支持多种订阅模式、流控机制、Ack 策略和高级功能(如死信队列、延迟重试等),适用于实时处理、事件驱动架构、流计算等多种场景。
📘 Pulsar Consumer 详解
一、Consumer 基本概念
1. 什么是 Consumer?
- Consumer 是消息的接收者,连接到 Pulsar Broker,从指定 Topic 的某个 Subscription(订阅) 中拉取消息。
- 每个 Consumer 必须指定:
- Topic 名称
- Subscription 名称
- 订阅模式(Exclusive / Shared / Failover / Key_Shared)
2. 核心职责
| 职责 | 说明 |
|---|---|
| ✅ 连接 Broker | 建立与集群的连接 |
| ✅ 拉取消息 | 从 Broker 接收消息(Push 模式为主) |
| ✅ 消息确认(Ack) | 显式确认已处理的消息 |
| ✅ 流量控制 | 控制预取数量,防止内存溢出 |
| ✅ Schema 支持 | 自动反序列化消息 |
| ✅ 错误处理 | 支持重试、死信队列、负确认(NACK) |
二、Consumer 创建与配置(Java 示例)
// 1. 创建 Pulsar 客户端
PulsarClient client = PulsarClient.builder()
.serviceUrl("pulsar://localhost:6650")
.build();
// 2. 构建 Consumer
Consumer<String> consumer = client.newConsumer(Schema.STRING)
.topic("persistent://mycompany/finance/payments")
.subscriptionName("payment-processor") // 订阅名称
.subscriptionType(SubscriptionType.Shared) // 订阅模式
.ackTimeout(30, TimeUnit.SECONDS) // Ack 超时(仅 Failover/Exclusive)
.acknowledgmentGroupTime(100, TimeUnit.MILLISECONDS) // 批量确认间隔
.receiverQueueSize(1000) // 预取队列大小(流控关键)
.maxTotalReceiverQueueSizeAcrossPartitions(50000) // 分区总预取限制
.subscriptionInitialPosition(SubscriptionInitialPosition.Earliest) // 从头开始消费
.negativeAckRedeliveryDelay(5, TimeUnit.SECONDS) // NACK 后重试延迟
.isAckReceiptEnabled(false) // 是否等待 Broker 的 Ack Receipt
.subscribe();
💡 提示:
Schema.STRING表示消息将被反序列化为字符串,Pulsar 支持多种 Schema 类型。
三、消息接收方式
Pulsar Consumer 支持两种主要的消息接收模式:
1. Listener 模式(异步回调) — 推荐用于高吞吐场景
- 注册一个回调函数,Broker 主动推送消息。
- 非阻塞,适合长时间运行的服务。
consumer = client.newConsumer(Schema.STRING)
.topic("payments")
.subscriptionName("processor")
.messageListener((consumer, msg) -> {
try {
System.out.println("Received: " + msg.getValue());
consumer.acknowledge(msg); // 手动确认
} catch (Exception e) {
consumer.negativeAcknowledge(msg); // 处理失败,立即重试
}
})
.subscribe();
✅ 优势:高吞吐、低延迟、易于集成异步框架。
2. Receive 模式(同步拉取)
- 主动调用
receive()方法拉取消息(可带超时)。 - 适用于控制流严格的场景。
while (true) {
Message<String> msg = consumer.receive(5, TimeUnit.SECONDS);
if (msg != null) {
try {
System.out.println("Received: " + msg.getValue());
consumer.acknowledge(msg);
} catch (Exception e) {
consumer.negativeAcknowledge(msg);
}
}
}
⚠️ 注意:需手动处理异常和确认。
四、消息确认机制(Acknowledgment)
Pulsar 要求消费者显式确认消息,确保不丢失。
1. Positive Ack(正确认)
- 表示消息已成功处理。
- Broker 删除该消息或更新游标。
consumer.acknowledge(msg); // 确认单条
consumer.acknowledge(messages); // 批量确认
2. Negative Ack(负确认,NACK)
- 表示消息处理失败,立即重新投递(不等待重试延迟)。
- 适用于瞬时错误(如依赖服务暂时不可用)。
consumer.negativeAcknowledge(msg);
⚠️ 频繁 NACK 可能导致消息风暴。
3. Ack Timeout(仅适用于 Exclusive / Failover)
- 如果消息在
ackTimeout内未被确认,Broker 会自动重发。 - 默认不启用,建议配合 NACK 使用。
.ackTimeout(30, TimeUnit.SECONDS)
❗ 注意:Shared 和 Key_Shared 模式不支持 Ack Timeout(由 Redelivery 机制替代)。
五、重试与死信队列(Retry & DLQ)
1. 自动重试机制
- Pulsar 支持配置最大重试次数。
- 通过 重试 Topic(Retry Topic) 实现延迟重试。
// 启用重试
Consumer<byte[]> consumer = client.newConsumer()
.topic("orders")
.subscriptionName("order-processor")
.enableRetry(true) // 开启重试
.deadLetterPolicy(DeadLetterPolicy.builder()
.maxRedeliverCount(5)
.retryLetterTopic("persistent://mycompany/finance/order-retry")
.deadLetterTopic("persistent://mycompany/finance/order-dlq")
.build())
.subscribe();
- 消息处理失败 → 进入 Retry Topic → 延迟重试 → 达到上限 → 进入 DLQ
2. 死信队列(DLQ)
- 存储最终无法处理的消息,便于后续排查或人工干预。
# 也可通过 Admin CLI 设置
pulsar-admin namespaces set-dead-letter-policy mycompany/finance \
--maxRedeliverCount 5 \
--deadLetterTopic dlq/payments-failed \
--retryLetterTopic retry/payments
六、流量控制(Flow Control)
防止消费者被消息“淹没”,通过 预取队列(Receiver Queue) 实现流控。
| 参数 | 说明 |
|---|---|
receiverQueueSize | 每个消费者最多预取的消息数(默认 1000) |
maxTotalReceiverQueueSizeAcrossPartitions | 所有分区总预取上限 |
| 工作机制 | Broker 只有在消费者还有空位时才推送消息 |
✅ 建议:根据消费者处理能力设置合理值,避免 OOM 或吞吐瓶颈。
七、Consumer 高级特性
1. Schema 支持(自动反序列化)
Schema<Order> schema = Schema.AVRO(Order.class);
Consumer<Order> consumer = client.newConsumer(schema)
.topic("orders")
.subscriptionName("order-consumer")
.subscribe();
Message<Order> msg = consumer.receive();
Order order = msg.getValue(); // 自动反序列化
✅ 优势:类型安全、兼容性检查、减少错误。
2. 从指定位置开始消费
.subscriptionInitialPosition(SubscriptionInitialPosition.Earliest) // 从头开始
.subscriptionInitialPosition(SubscriptionInitialPosition.Latest) // 从最新开始
或通过时间重置:
pulsar-admin topics reset-cursor -s subscription-name -t "2024-01-01T00:00:00Z" topic-name
3. 消息过滤(Consumer Key Filter)
仅接收特定 Key 的消息(实验性功能):
.consumerKeyFilter(key -> key.startsWith("VIP-"))
4. 读取未确认消息(Backlog)
- Consumer 可以查看当前订阅的 backlog(未消费消息数)。
- 用于监控积压情况。
long backlog = consumer.getApproximateBacklog();
八、不同订阅模式下的 Consumer 行为对比
| 订阅模式 | 并发消费 | 顺序性 | Ack 机制 | 典型用法 |
|---|---|---|---|---|
| Exclusive | ❌ 单消费者 | ✅ 全局顺序 | Ack / AckTimeout | 单实例任务 |
| Shared | ✅ 多消费者 | ❌ 无序 | Ack / NACK | 高吞吐队列 |
| Failover | ❌ 主备 | ✅ 全局顺序 | Ack / AckTimeout | 顺序 + HA |
| Key_Shared | ✅ 多消费者 | ✅ Key 级顺序 | Ack / NACK | 分区顺序处理 |
九、最佳实践建议
| 实践 | 建议 |
|---|---|
| ✅ 使用 Listener 模式 | 高吞吐、低延迟 |
✅ 合理设置 receiverQueueSize | 防 OOM,平衡吞吐与延迟 |
| ✅ 启用 Schema | 保证数据一致性 |
| ✅ 开启重试 + DLQ | 提升系统容错能力 |
| ✅ 避免长时间不 Ack | 防止消息重复 |
| ✅ 监控 Backlog | 及时发现消费延迟 |
✅ 使用有意义的 subscriptionName | 便于运维 |
| ✅ 处理异常时使用 NACK | 而不是抛异常导致进程退出 |
十、可视化 Consumer 工作流程
+---------------------+
| Pulsar Broker |
| - 推送消息到 Consumer |
| - 基于预取队列流控 |
+----------+----------+
|
v
+----------+----------+
| Receiver Queue |
| (最多 receiverQueueSize 条) |
+----------+----------+
|
v
[Message Listener]
|
v
+----------+----------+
| Application Logic |
| - 处理消息 |
| - 调用 acknowledge() |
| - 失败则 negativeAck |
+----------+----------+
|
v
ACK / NACK
|
v
Broker 更新游标
✅ 总结
| 特性 | 说明 |
|---|---|
| ✅ 多种接收模式 | Listener(推荐)、Receive |
| ✅ 灵活的 Ack 机制 | Ack / NACK / AckTimeout |
| ✅ 高级错误处理 | 重试 Topic + 死信队列 |
| ✅ 流量控制 | Receiver Queue 防 OOM |
| ✅ Schema 支持 | 自动反序列化 |
| ✅ 支持重播 | 可从任意时间点重新消费 |
| ✅ 多语言 SDK | Java, Python, Go, Node.js, C++ 等 |
📌 一句话总结:
Consumer 是数据处理的终点 —— 合理配置订阅模式、启用重试与 DLQ、控制预取队列,是构建稳定、可靠消息消费系统的关键。
1180

被折叠的 条评论
为什么被折叠?



