一、正文
Namespace下的Topic是分Bundle进行管理的,每个Namespace都是一个哈希环,而Bundle负责管理环上某个范围上的Topic。通过这种方式可以更好的进行Topic的管理。当某个Bundle上负责的Topic越来越多时,会导致负责该Bundle的Broker节点压力变大。因此Pulsar还提供了Bundle分裂的机制,这个机制支持自动触发以及手动触发,今天这篇文章就从源码的角度分析手动触发Bundle分裂时服务端会发生什么
主动触发Bundle分裂操作方式
bin/pulsar-admin namespaces bundles public/default
//输出如下
{
"boundaries" : [ "0x00000000", "0x08000000", "0x10000000", "0x20000000", "0x30000000", "0x40000000", "0x50000000", "0x60000000", "0x70000000", "0x80000000", "0x90000000", "0xa0000000", "0xb0000000", "0xc0000000", "0xd0000000", "0xe0000000", "0xf0000000", "0xffffffff" ],
"numBundles" : 17
}
//指定某个bundle进行分裂
bin/pulsar-admin namespaces split-bundle --bundle 0x00000000_0x10000000 public/default
二、源码解析
Pulsar管理流相关的操作都是通过HTTP的方式,因为需要支持多种客户端类型(http、client、cli)。服务端处理这些操作都在admin模块下,如下图,本次要聊的bundle分裂就在Namespaces方法中
首先从Namespaces的splitNamespaceBundle进行跟踪
public void splitNamespaceBundle(
....
@QueryParam("splitAlgorithmName") String splitAlgorithmName, //指定bundle分裂算法
@ApiParam("splitBoundaries") List<Long> splitBoundaries) {
//校验参数格式以及是否存在对应的namespace
validateNamespaceName(tenant, namespace);
//异步进行分裂操作
internalSplitNamespaceBundleAsync(bundleRange, authoritative, unload, splitAlgorithmName, splitBoundaries)
.thenAccept(__ -> {
....
})
.exceptionally(ex -> {
....
});
}
可以看到最外层只是做些参数校验,那么就继续跟踪internalSplitNamespaceBundleAsync方法,如下
protected CompletableFuture<Void> internalSplitNamespaceBundleAsync(String bundleName,
boolean authoritative,
boolean unload,
String splitAlgorithmName,
List<Long> splitBoundaries) {
return validateSuperUserAccessAsync() //权限校验
.thenAccept(__ -> {
checkNotNull(bundleName, "BundleRange should not be null");
log.info("[{}] Split namespace bundle {}/{}", clientAppId(), namespaceName, bundleName);
//获取当前集群所支持的bundle分裂算法,这里是硬编码的固定四种
List<String> supportedNamespaceBundleSplitAlgorithms =
pulsar().getConfig().getSupportedNamespaceBundleSplitAlgorithms();
//此处省去参数检查逻辑
....
}
})
.thenCompose(__ -> {
//此处省去参数检查逻辑
....
})
.thenCompose(__ -> validatePoliciesReadOnlyAccessAsync()) //权限校验
.thenCompose(__ -> getBundleRangeAsync(bundleName)) //获取要分裂的bundle的范围
.thenCompose(bundleRange -> {
return getNamespacePoliciesAsync(namespaceName)
.thenCompose