前几篇介绍过生产者创建的底层实现,本章介绍发送的实现细节
一、分区生产者和非分区生产发送的差异
消息发送存在分区和非分区的Producer代码实现,先介绍一下区别点,然后后面流程都一样。
分区Producer需要实现选择一个具体的Producer实现,怎么选择的呢?
创建生产者时会配置路由策略,看一下实现:
public class PartitionedProducerImpl<T> {
// 调用是在PartitionedProducerImpl构造中
private MessageRouter getMessageRouter() {
MessageRouter messageRouter;
// 从配置中获取路由模式
MessageRoutingMode messageRouteMode = conf.getMessageRoutingMode();
switch (messageRouteMode) {
// 自定义实现
case CustomPartition:
messageRouter = checkNotNull(conf.getCustomMessageRouter());
break;
// 多个分区中随机固定一个
case SinglePartition:
messageRouter = new SinglePartitionMessageRouterImpl(
ThreadLocalRandom.current().nextInt(topicMetadata.numPartitions()), conf.getHashingScheme());
break;
// 轮询
case RoundRobinPartition:
default:
messageRouter = new RoundRobinPartitionMessageRouterImpl(
conf.getHashingScheme(),
ThreadLocalRandom.current().nextInt(topicMetadata.numPartitions()),
conf.isBatchingEnabled(),
TimeUnit.MICROSECONDS.toMillis(conf.batchingPartitionSwitchFrequencyIntervalMicros()));
}
return messageRouter;
}
}
具体实现比较简单就不介绍了。
看一下分区Producer调用发送代码:
public class PartitionedProducerImpl<T> {
CompletableFuture<MessageId> internalSendWithTxnAsync(Message<?> message, Transaction txn) {
// 路由实现类返回一个分区数
int partition = routerPolicy.choosePartition(message, topicMetadata);
// 获取对应分区Producer的实现
// 集合是按分区Producer创建顺序add的
return producers.get(partition).internalSendWithTxnAsync(message, txn);
}
}
上面调用internalSendWithTxnAsync是非分区ProducerImpl中的发送,后面都一样了,接下来不会再说分区和非分区了。
二、生产者发送实现
public class ProducerImpl<T> {
CompletableFuture<MessageId> internalSendAsync(Message<?> message) {
CompletableFuture<MessageId> future = new CompletableFuture<>();
// 创建生产者时是可以配置拦截器的,这里是发送前调用拦截器
MessageImpl<?> interceptorMessage = (MessageImpl) beforeSend(message);
// netty堆外内存的引用计数+1,意味着在没有收到发送成功响应时堆外内存空间一直占用
interceptorMessage.getDataBuffer().retain();
// 拦截返回的消息可能修改过,防止后面调用出现NPE,Properties如果空初始化Collections.emptyMap()
if (interceptors != null) {
interceptorMessage.getProperties();
}
// 发送消息,添加一个回调,当收到服务端响应成功时调用sendComplete
sendAsync(interceptorMessage, new SendCallback() {
SendCallback nextCallback = null;
MessageImpl<?> nextMsg = null;
long createdAt = System.nanoTime();
@Override
public CompletableFuture<MessageId> getFuture() {
return future;
}
@Override
public SendCallback getNextSendCallback() {
return nextCallback;
}
@Override
public MessageImpl<?> getNextMessage() {
return nextMsg;
}
@Override
public void sendComplete(

本文深入剖析了Pulsar消息发送的实现细节,包括分区与非分区生产者的选择策略及消息发送流程,重点关注了消息压缩、加密及批量发送等关键技术点。
最低0.47元/天 解锁文章
3412

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



