Pulsar源码解析-服务端-消费者创建的底层实现

上一篇介绍的是消费者客户端的创建,本章解析服务端创建

一、消费者服务端创建入口

由于代码量较多,省略非重点

public class ServerCnx {

protected void handleSubscribe(final CommandSubscribe subscribe) {
		// 参数含义客户端消费者构造中都介绍过
        final long requestId = subscribe.getRequestId();
        final long consumerId = subscribe.getConsumerId();
        TopicName topicName = validateTopicName(subscribe.getTopic(), requestId, subscribe);
        final String subscriptionName = subscribe.getSubscription();
        final SubType subType = subscribe.getSubType();
        final String consumerName = subscribe.hasConsumerName() ? subscribe.getConsumerName() : "";
        final boolean isDurable = subscribe.isDurable();
        final MessageIdImpl startMessageId = subscribe.hasStartMessageId() ? new BatchMessageIdImpl(
                subscribe.getStartMessageId().getLedgerId(), subscribe.getStartMessageId().getEntryId(),
                subscribe.getStartMessageId().getPartition(), subscribe.getStartMessageId().getBatchIndex())
                : null;
        final int priorityLevel = subscribe.hasPriorityLevel() ? subscribe.getPriorityLevel() : 0;
        final boolean readCompacted = subscribe.hasReadCompacted() && subscribe.isReadCompacted();
        final Map<String, String> metadata = CommandUtils.metadataFromCommand(subscribe);
        final InitialPosition initialPosition = subscribe.getInitialPosition();
        final long startMessageRollbackDurationSec = subscribe.hasStartMessageRollbackDurationSec()
                ? subscribe.getStartMessageRollbackDurationSec()
                : -1;
        final SchemaData schema = subscribe.hasSchema() ? getSchema(subscribe.getSchema()) : null;
        final boolean isReplicated = subscribe.hasReplicateSubscriptionState()
                && subscribe.isReplicateSubscriptionState();
        final boolean forceTopicCreation = subscribe.isForceTopicCreation();
        final KeySharedMeta keySharedMeta = subscribe.hasKeySharedMeta()
              ? new KeySharedMeta().copyFrom(subscribe.getKeySharedMeta())
              : emptyKeySharedMeta;
		// 查询权限
        CompletableFuture<Boolean> isAuthorizedFuture = isTopicOperationAllowed(
                topicName,
                subscriptionName,
                TopicOperation.CONSUME
        );
        // 权限校验
        isAuthorizedFuture.thenApply(isAuthorized -> {
            if (isAuthorized) {
                        CompletableFuture<Consumer> consumerFuture = new CompletableFuture<>();
                        // 服务端保存消费者实例
                        CompletableFuture<Consumer> existingConsumerFuture = consumers.putIfAbsent(consumerId,
                                consumerFuture);
						// 已存在且已创建完成直接返回
                        if (existingConsumerFuture != null) {
                            if (existingConsumerFuture.isDone() && !existingConsumerFuture.isCompletedExceptionally()) {
                                Consumer consumer = existingConsumerFuture.getNow(null);
                                commandSender.sendSuccessResponse(requestId);
                                return null;
                            } else {
                                return null;
                            }
                        }
						// forceTopicCreation是客户端传的是否自动创建
						// isAllowAutoTopicCreation是broker.conf配置的是否自动创建
                        boolean createTopicIfDoesNotExist = forceTopicCreation
                                && service.isAllowAutoTopicCreation(topicName.toString());
						// 之前讲producer服务端创建时也有这么一行
						// service.getOrCreateTopic(topicName.toString())
						// 本质一样,创建topic
						// 所以可以得出:消费者或生产者创建时都会创建topic,具体创建过程看生产者中的介绍
                        service.getTopic(topicName.toString(), createTopicIfDoesNotExist)
                                .thenCompose(optTopic -> {
                                    Topic topic = optTopic.get();
                                    // 没有创建成功 例如不允许自动创建订阅
                                    // broker.conf中配置,默认允许
                                    boolean rejectSubscriptionIfDoesNotExist = isDurable
                                        && !service.isAllowAutoSubscriptionCreation(topicName.toString())
                                        && !topic.getSubscriptions().containsKey(subscriptionName);

                                    if (rejectSubscriptionIfDoesNotExist) {
                                        return 异常...
                                    }
									// schema校验
                                    if (schema != null) {
                                        return topic.addSchemaIfIdleOrCheckCompatible(schema)
                                                .thenCompose(v -> 
                                                // 创建订阅
                                                topic.subscribe(
                                                        ServerCnx.this, subscriptionName, consumerId,
                                                        subType, priorityLevel, consumerName, isDurable,
                                                        startMessageId, metadata,
                                                        readCompacted, initialPosition, startMessageRollbackDurationSec,
                                                        isReplicated, keySharedMeta));
                                    } else {
                                        return topic.subscribe(ServerCnx.this, subscriptionName, consumerId,
                                            subType, priorityLevel, consumerName, isDurable,
                                            startMessageId, metadata, readCompacted, initialPosition,
                                            startMessageRollbackDurationSec, isReplicated, keySharedMeta);
                                    }
                                })
                                .thenAccept(consumer -> {
                                	// 响应客户端
                                	// 就是之前讲的消费者客户端的打开连接创建消费者那里
                                	// 更新消费者客户端状态Ready,如果是单消费者会发起拉取请求
                                    if (consumerFuture.complete(consumer)) {
                                        commandSender.sendSuccessResponse(requestId);
                                    } else {
                                        try {
                                            consumer.close();
                                        } catch (BrokerServiceException e) {
                                        }
                                        consumers.remove(consumerId, consumerFuture);
                                    }

                                })
                                .exceptionally(exception -> {
                                });
                    } else {
                        ctx.writeAndFlush(Commands.newError(requestId, ServerError.AuthorizationError, msg));
                    }
                    return null;
        }).exceptionally(ex -> {
            return null;
        });
    }
}

二、Subscription创建

重点在topic.subscribe(...)

public class PersistentTopic {

    public CompletableFuture<Consumer> subscribe(final TransportCnx cnx, String subscriptionName, long consumerId,
                                                 SubType subType, int priorityLevel, String consumerName,
                                                 boolean isDurable, MessageId startMessageId,
                                                 Map<String, String> metadata, boolean readCompacted,
                                                 InitialPosition initialPosition,
                                                 long startMessageRollbackDurationSec,
                                                 boolean replicatedSubscriptionState,
                                                 KeySharedMeta keySharedMeta) {

        final CompletableFuture<Consumer> future = new CompletableFuture<>();
        if (cnx.clientAddress() != null && cnx.clientAddress().toString().contains(":")) {
            SubscribeRateLimiter.ConsumerIdentifier consumer = new SubscribeRateLimiter.ConsumerIdentifier(
                    cnx.clientAddress().toString().split(":")[0], consumerName, consumerId);
            if (subscribeRateLimiter.isPresent() && (!subscribeRateLimiter.get().subscribeAvailable(consumer)
                    || !subscribeRateLimiter.get().tryAcquire(consumer))) {
                return future;
            }
        }

        lock.readLock().lock();
        try {
            if (isFenced) {
                return future;
            }
            // 统计消费者
            handleConsumerAdded(subscriptionName, consumerName);
        } finally {
            lock.readLock().unlock();
        }

		// 创建订阅
		// initialPosition是从最新的还是最老的开始消费,默认最新
		// startMessageRollbackDurationSec 配置的时间,默认0
		// replicatedSubscriptionState是否复制 默认false,消费者客户端配置
        CompletableFuture<? extends Subscription> subscriptionFuture = isDurable ? //
                getDurableSubscription(subscriptionName, initialPosition, startMessageRollbackDurationSec,
                        replicatedSubscriptionState)
                : getNonDurableSubscription(subscriptionName, startMessageId, initialPosition,
                startMessageRollbackDurationSec);

        int maxUnackedMessages = isDurable
                ? getMaxUnackedMessagesOnConsumer()
                : 0;

        subscriptionFuture.thenAccept(subscription -> {
        	// 创建消费者
            Consumer consumer = new Consumer(subscription, subType, topic, consumerId, priorityLevel, consumerName,
                    maxUnackedMessages, cnx, cnx.getAuthRole(), metadata,
                    readCompacted, initialPosition, keySharedMeta, startMessageId);
                    // 把消费者添加到订阅中
                    // 可以发现,订阅才是外层,管理具体消费者实例
            addConsumerToSubscription(subscription, consumer).thenAccept(v -> {
                checkBackloggedCursors();
                if (!cnx.isActive()) {
                    // 异常
                } else {
                	// 对等集群复制
                    checkReplicatedSubscriptionControllerState();
                    future.complete(consumer);
                }
            }).exceptionally(e -> {
                return null;
            });
        }).exceptionally(ex -> {
            return null;
        });

        return future;
    }
}

我们只分析最重要最常用的持久化订阅
继续getDurableSubscription

private CompletableFuture<Subscription> getDurableSubscription(String subscriptionName,
            InitialPosition initialPosition, long startMessageRollbackDurationSec, boolean replicated) {
        CompletableFuture<Subscription> subscriptionFuture = new CompletableFuture<>();
        // 是否超过topic最大创建的订阅数量
        if (checkMaxSubscriptionsPerTopicExceed(subscriptionName)) {
            return subscriptionFuture;
        }

        Map<String, Long> properties = PersistentSubscription.getBaseCursorProperties(replicated);
		// 由打开一个Cursor
        ledger.asyncOpenCursor(Codec.encode(subscriptionName), initialPosition, properties, new OpenCursorCallback() {
            @Override
            public void openCursorComplete(ManagedCursor cursor, Object ctx) {
				// 创建持久化订阅实例
                PersistentSubscription subscription = subscriptions.computeIfAbsent(subscriptionName,
                        name -> createPersistentSubscription(subscriptionName, cursor, replicated));

                if (replicated && !subscription.isReplicated()) {
                    subscription.setReplicated(replicated);
                }
				// 重置起始读、删除位置
                if (startMessageRollbackDurationSec > 0) {
                    resetSubscriptionCursor(subscription, subscriptionFuture, startMessageRollbackDurationSec);
                } else {
                    subscriptionFuture.complete(subscription);
                }
            }

            @Override
            public void openCursorFailed(ManagedLedgerException exception, Object ctx) {
                decrementUsageCount();
                subscriptionFuture.completeExceptionally(new PersistenceException(exception));
                if (exception instanceof ManagedLedgerFencedException) {
                    close();
                }
            }
        }, null);
        return subscriptionFuture;
    }

ledger.asyncOpenCursor是创建ManagedCursor和数据初始化等
ManagedCursor从ManagedLedger中读数据,提供了各种读的api。
ManagedCursor和ManagedLedger底层细节专题单独讲,目前只需知道它们的作用和关系。
目前我们需要了解消息如何发送,如何接收,这个过程中分别在客户端和服务端如何实现的

我只需要知道在这里完成了Subscription创建

Subscription是根据订阅名称1对1创建,不同订阅名是广播消费,消费者名称生成的是consumer实例。Subscription根据consumer构建成Dispatcher进行消息分发,Dispatcher由订阅类型决定。

下一章介绍Subscription拉取请求的实现。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
pulsar-java-spring-boot-starter是一个用于在Spring Boot应用程序中集成Apache Pulsar消息队列的开源库。Apache Pulsar是一个可扩展的、低延迟的分布式消息传递平台,它具有高吞吐量和高可靠性的特点。 pulsar-java-spring-boot-starter允许开发人员在Spring Boot应用程序中轻松地发送和接收Pulsar消息。它提供了一组容易使用的注解和工具类,简化了与Pulsar集群的交互。 使用pulsar-java-spring-boot-starter,开发人员可以通过添加依赖和配置一些属性来快速集成Pulsar到他们的Spring Boot应用程序中。一旦集成完成,开发人员可以使用注解来定义消息的生产者和消费者。通过生产者注解,开发人员可以将消息发送到Pulsar集群,并指定消息的主题和内容。通过消费者注解,开发人员可以订阅Pulsar主题,并定义接收和处理消息的方法。 除了基本的生产者和消费者功能,pulsar-java-spring-boot-starter还提供了一些其他特性。例如,它支持失败重试机制,当消息发送或接收出现问题时,可以自动重试。它还支持消息过滤器,可以按条件过滤接收的消息。而且,它还提供了一些监控和管理功能,可以方便地监控消息的生产和消费情况。 总之,pulsar-java-spring-boot-starter为Spring Boot开发人员提供了一种方便、快捷地集成Apache Pulsar消息队列的方法。它简化了与Pulsar集群的交互,提供了易于使用的注解和工具类,让开发人员可以更专注于业务逻辑的实现

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值