目录
客户端 API 优化和封装了 Pulsar 的客户端和 broker 之间的通信协议,并公开了一个简单直观的 API 供应用程序使用。
在后台,当前的 Pulsar 官方客户端库工具支持对 brokers 进行透明的重连和容错切换,并在broker 确认之前对消息进行排队,以及回退重连等。
1、Client setup phase 客户端连接阶段
在应用程序创建生产者或消费者之前,Pulsar 客户端工具需要进行初始化,初始化包括两个步骤:// 第一步确认主题所有者,第二步创建主题的生产者或者消费者
- 客户端向 broker 发送 HTTP 查找请求,确定主题的所有者。请求会到达多个活跃的 brokers 中的其中一个上,该 broker 通过 zookeeper 的元数据查找为主题提供服务的 broker,如果没有 broker 为该主题提供服务,那么会尝试将主题分配给负载最少的 broker。
- 一旦客户端库拥有 broker 的地址,它会创建一个TCP连接(或重用池中现有的连接)并进行身份验证。在连接过程中,客户端和 broker 会通过自定义的协议交换二进制命令。如果此时客户端向 broker 发送创建生产者或者消费者的指令,在验证授权通过后,broker 会执行该指令。
每当 TCP 连接中断时,客户端会重新初始化此连接阶段,并尝试重建生产者或消费者,直到操作成功。
2、Reader interface 读取接口
在 Pulsar 中,标准的 Reader 接口会涉及到如下操作:让消费者能够监听主题、处理的传入消息,以及在处理完消息后发送确认通知。当创建新的订阅时,消费者会从该订阅创建后,生产的第一条消息开始消费(默认)。当使用已经存在的订阅时,消费者会从该订阅中没有被确认的第一条消息开始消费。总之,使用 Reader 接口,对于上边场景,plusar 都能够自动的管理订阅游标,并响应消息确认。
Pulsar 中的 Reader 接口能够让应用程序手动的管理订阅游标。比如,当你使用 reader 而不是 consumer 连接主题时,你可以指定 reader 从哪一个位置开始读取消息,reader 接口允许你可从主题中以下位置开始读取消息:
- 主题中最早可用消息(earliest available message)// 从主题中第一条数据开始
- 主题中最新可用消息(latest available message)// 从最新生产的数据开始
- 最早和最晚之间的其他消息(between the earliest and the latest)/ 指定位置。如果选择此选项,则需要显式提供消息 ID。应用程序会提前获取此消息 ID(会从持久数据存储中或缓存中获取它)。
Reader 接口在某些场景下很有用,比如,当 Pulsar 需要保证为所有消息都提供有效处理的时候,这种情况下,流处理平台需要能够支持从主题中的指定消息处开始消费。Reader 接口为 Pulsar 客户端提供了在主题中手动定位资源的低级抽象。// 支持手动定位资源
在 Pulsar 内部,Reader 接口是作为消费者实现的,该消费者使用独占模式,同时使用随机分配的订阅名称,订阅的模式使用的是非持久化游标。// 消费者重连时将丢失消费位置
[ IMPORTANT ] 重要
与订阅或者消费者不同,Reader 本质上是不持久的,它不会阻止主题中的数据被删除,因此强烈建议配置数据保留方案( data retention)。如果主题中的数据没有保留足够的时间,那么尚未被消费的消息可能会已经被删除,从而可能会导致 Reader 跳读消息。为主题配置数据保留可以保证 Reader 有一定的时间来处理消息。
请注意,Reader 可以有消息存储 backlog 日志(消息积压),但是该日志仅用于帮助用户了解 Reader 的读取情况,任何积压配额计算都不应该考虑该指标。
消费者 Consumers
// Reader 和 Comsumer 的区别,可以消费的位置不同,但是这种策略应该都是可以配置的,可以作为区别吗?
Reader
下面是一个 Java 的代码示例,创建 Reader,读取主题中最早可用的消息:
import org.apache.pulsar.client.api.Message;
import org.apache.pulsar.client.api.MessageId;
import org.apache.pulsar.client.api.Reader;
// Create a reader on a topic and for a specific message (and onward)
Reader<byte[]> reader = pulsarClient.newReader()
.topic("reader-api-test")
.startMessageId(MessageId.earliest) // 最早可用的消息
.create();
while (true) {
Message message = reader.readNext();
// Process the message
}
创建 Reader,读取主题中最新可用的消息:
Reader<byte[]> reader = pulsarClient.newReader()
.topic(topic)
.startMessageId(MessageId.latest) // 最新可用
.create();
创建 Reader,读取主题中指定位置的消息:
byte[] msgIdBytes = // Some byte array
MessageId id = MessageId.fromByteArray(msgIdBytes);
Reader<byte[]> reader = pulsarClient.newReader()
.topic(topic)
.startMessageId(id) // 指定读取消息的Id,从此处开始读
.create();
至此,Reader 接口介绍完毕。