RocketMQ之MQClientInstance

齐栋
2023-12-01

MQClientInstance不是对外应用类,也就是说用户不需要自己实例化使用他。并且,MQClientInstance的实例化并不是直接new后使用,而是通过MQClientManager这个类型。MQClientManager是个单例类,使用饿汉模式设计保证线程安全。他的作用是提供MQClientInstance实例,RocketMQ认为,MQClientInstance的实例是可以复用的实例,只要client相关特征参数相同,就会复用一个MQClientInstance实例,我们可以看看源码

public MQClientInstance getAndCreateMQClientInstance(final ClientConfig clientConfig, RPCHook rpcHook) {
    String clientId = clientConfig.buildMQClientId();
    MQClientInstance instance = this.factoryTable.get(clientId);
    if (null == instance) {
        instance =
            new MQClientInstance(clientConfig.cloneClientConfig(),
                this.factoryIndexGenerator.getAndIncrement(), clientId, rpcHook);
        MQClientInstance prev = this.factoryTable.putIfAbsent(clientId, instance);
        if (prev != null) {
            instance = prev;
            log.warn("Returned Previous MQClientInstance for clientId:[{}]", clientId);
        } else {
            log.info("Created new MQClientInstance for clientId:[{}]", clientId);
        }
    }
    return instance;
}

所以只要ClientConfig里的相关参数一致,这些Client会复用一个MQClientInstance,使用的时候需要注意,你的程序里的Client和MQClientInstance的对应关系。下面我们来看看RocketMQ对参数配置如何的Client复用一个MQClientInstance,简单来说就是IP@instanceName@unitName,这么一个串,其中IP我不解释了,InstanceName可以设置,Producer和Consucer都有相应的API设置,如果不设置使用缺省值即Client的PID,unitName不设置缺省为null,当然你可以DefaultMQProducer#setUnitName()这个方法设置这个值,这个方法是继承自ClientConfig类的。

public String buildMQClientId() {
    StringBuilder sb = new StringBuilder();
    sb.append(this.getClientIP());

    sb.append("@");
    sb.append(this.getInstanceName());
    if (!UtilAll.isBlank(this.unitName)) {
        sb.append("@");
        sb.append(this.unitName);
    }

    return sb.toString();
}

那复用一个MQClientInstance会有怎么的结果呢?这种情况会出现在你在一个JVM里启动了多个Producer时,且没有设置instanceName和unitName,那么这两个Producer会公用一个MQClientInstance,发送的消息会路由到同一个集群。例如,你起了两个Producer,并且配置的NameServer地址不一样,本意是让这两个Producer往不同集群上分配消息,但是由于共用了一个MQClientInstance,这个MQClientInstance是基于先来的Producer配置构建的,第二个Producer和他公用后被认为是同一instance,配置是相同的,消息的路由就是相同的,就没有达到你想要的效果。

 类似资料: