Pulsar源码解析-服务端-Producer消息发送底层实现

Pulsar消息发送流程
本文详细解析了Pulsar消息系统中消息从客户端发送到服务端的整个过程,包括客户端和服务端的主要处理逻辑,消息的批量发送及持久化机制,并深入探讨了涉及的多层回调机制。

之前介绍了客户端的发送实现,客户端发送到服务端,服务端怎么处理消息的我们看一下源码实现

一、发送消息服务端入口

public class ServerCnx {
   
   

   protected void handleSend(CommandSend send, ByteBuf headersAndPayload) {
   
   
   		// 获取创建时存储的生产者
        CompletableFuture<Producer> producerFuture = producers.get(send.getProducerId());
        Producer producer = producerFuture.getNow(null);
        // 校验非持久化的等待消息数是否超过最大值默认1000
        if (producer.isNonPersistentTopic()) {
   
   
            if (nonPersistentPendingMessages > maxNonPersistentPendingMessages) {
   
   
                final long producerId = send.getProducerId();
                final long sequenceId = send.getSequenceId();
                final long highestSequenceId = send.getHighestSequenceId();
                service.getTopicOrderedExecutor().executeOrdered(producer.getTopic().getName(), SafeRun.safeRun(() -> {
   
   
                    commandSender.sendSendReceiptResponse(producerId, sequenceId, highestSequenceId, -1, -1);
                }));
                producer.recordMessageDrop(send.getNumMessages());
                return;
            } else {
   
   
                nonPersistentPendingMessages++;
            }
        }
		// 校验当前发送速率和等待发送的消息是否超过最大值
        startSendOperation(producer, headersAndPayload.readableBytes(), send.getNumMessages());
		// 省略事务相关
		
		// HighestSequenceId和SequenceId
		// 客户端会批量发送,一批里每个消息SequenceId都不一样(一批也可能只有一条),有大有小
		// 一批中最大那个是highestSequenceId,最小的是lowestSequenceId,在这里最小的也是send.getSequenceId()
		// 因为批量消息的SequenceId设置的是第一条添加进来的消息SequenceId
        if (send.hasHighestSequenceId() && send.getSequenceId() <= send.getHighestSequenceId()) {
   
   
        	// 批量发送
            producer.publishMessage(send.getProducerId(), send.getSequenceId(), send.getHighestSequenceId(),
                    headersAndPayload, send.getNumMessages(), send.isIsChunk(), send.isMarker());
        } else {
   
   
        	// 单条
            producer.publishMessage(send.getProducerId(), send.getSequenceId(), headersAndPayload,
                    send.getNumMessages(), send.isIsChunk(), send.isMarker());
        }
    }
}

重点在producer.publishMessage(...),我们分析最复杂的场景批量发送。

二、Producer中的发送,第一层回调MessagePublishContext

public class Producer {
   
   

    public void publishMessage(long producerId, long lowestSequenceId, long highestSequenceId,
            ByteBuf headersAndPayload, long batchSize, boolean isChunked, boolean isMarker) {
   
   
            // 最小比最大还大肯定客户端的批量发送有问题
        if (lowestSequenceId > highestSequenceId) {
   
   
            cnx.execute(() -> {
   
   
                cnx.getCommandSender().sendSendError(producerId, highestSequenceId, ServerError.MetadataError,
                        "Invalid lowest or highest sequence id");
                cnx.completedSendOperation(isNonPersistentTopic, headersAndPayload.readableBytes());
            });
            return;
        }
        // 主要验证消息的完整性、加密、统计发送速率用于发送限流
        if (checkAndStartPublish(producerId, highestSequenceId, headersAndPayload, batchSize)) {
   
   
        	// 发送
            publishMessageToTopic(headersAndPayload, lowestSequenceId, highestSequenceId, batchSize, isChunked,
                    isMarker);
        }
    }
}

可以看到重点在publishMessageToTopic(...)

    private void publishMessageToTopic(ByteBuf headersAndPayload, long lowestSequenceId, long highestSequenceId,
                                       long batchSize, boolean isChunked, boolean isMarker) {
   
   
          // 最终还是topic调用发送
          // MessagePublishContext 把发送的参数都放入到这个请求上下文对象
          // 同时它也是发送的回调函数
        topic.publishMessage(headersAndPayload,
                MessagePublishContext.get(this, lowestSequenceId,
                        highestSequenceId, msgIn, headersAndPayload.readableBytes(), batchSize,
                        isChunked, System.nanoTime(), isMarker));
    }

接着分析持久化topic的发送
非持久化实现:接到消息,找到topic上订阅的消费者分发给它,如果存在对等集群,同步一份过去。没了

三、Topic中的发送,第二层回调PersistentTopic

@Override
public class PersistentTopic {
   
   

    public void publishMessage(ByteBuf headersAndPayload, PublishContext publishContext) {
   
   
    	// 等待发送的消息数+1,减1正常是在发送成功的回调里,后面会分析
        pendingWriteOps.incrementAndGet();
        // topic可能被删了
        if (isFenced) {
   
   
            publishContext.completed(new TopicFencedException("fenced"), -1, -1);
            // 上面说的等待数减1,后面的过程有异常都得减1
            // 还有:当前topic关联的所有生产消费者全部断开关闭,当前ledger关闭,Bundle关闭,同步到对等集群
            // 一句话:topic相关的基本全部清空
            decrementPendingWriteOpsAndCheck();
            return;
        }
        // 校验消息是否超过配置的最大 
        // 该配置精确到topic级别
        if (isExceedMaximumMessageSize(headersAndPayload
评论 5
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值