RocketMQ:The producer group has been created before, specify another name please.

来源:互联网 发布:打鱼平台游戏源码 编辑:程序博客网 时间:2024/06/05 13:18

RocketMQ新创建生产者时报异常:
The producer group[ ] has been created before, specify another name please.

发送消息时报异常:
com.alibaba.rocketmq.client.exception.MQClientException: The producer service state not OK, CREATE_JUST

解决办法:
new DefaultMQProducer时,提供instance name,而且instance name唯一。

producer.setInstanceName(RunTimeUtil.getRocketMqUniqeInstanceName());

注:我的使用场景是:消费者拿到消息后再创建生产者,将消息发送出去。消费时,是多线程的,如果同时发过来多条消息,就会导致多线程创建生产者,生产者被重复创建了,从而报上面的异常。如果每次只发一条消息,等消费完了再发下一条,即使不设置instance name,也不会出现上面的异常。
另外,虽然设置instance name,可以解决此问题,但根源还是用法不对。


为什么提供唯一instance name后,每次再创建DefaultMQProducer就不会报:The producer group[ ] has been created before, specify another name please.了呢?

我们分析一下源码,来查找原因:

  • 首先producer创建后,启动:
    这里写图片描述

    此处的producer没有设置instance name。

  • 通过上面的start()方法,调用到如下start方法,这段代码是producer启动执行的核心代码。
    这里写图片描述

说明一下,
图中1处是对instance name的处理,如果instance name没有指定,则取pid作为instance name;
图中2处是根据client id获取client instance,这个client id是由client ip加instance name组成。如果client id存在,则取出对应的client instance,如果client id不存在,则创建并保存client instance;
图中3处是注册生产者,如果生产者之前注册过,就会输出异常。

  • 上图中1处的代码展开:
    这里写图片描述
    这里写图片描述

一开始instance name没有指定,那么会默认给分配一个缺省的名字:DEFAULT,因为instanceName等于DEFAULT,所以获取pid(整数,例如:76052)作为instance name。一个实例中,每次获取的pid肯定是一样的。

  • 上图2处的代码展开:
    这里写图片描述

图中2.1处生成clientId,这个client id是由client ip加instance name组成。因为instance name在之前创建producer时没有指定一个唯一字符串,所以取的是pid。factoryTable之前没有保存过该clientId,所以new一个MQClientInstance,并放到factoryTable中。等下次再次创建producer时,因为pid一致,所以clientId也一样,从factoryTable中就get到之前创建的那个MQClientInstance。

  • 上图3处的代码展开:
    这里写图片描述

从2处得到MQClientInstance,通过他注册生产者(生产者加入producerTable),如果之前保存过该生产者,返回false。

分析:第一次:创建producer时,没有指定instance name,所以取pid(假设为76052)作为instance name,后面的clientId等于ip+76052,factoryTable没有此clientId,创建MQClientInstance并写入factoryTable,返回此MQClientInstance。
使用此MQClientInstance去registerProducer,因为MQClientInstance是new出来的,所以MQClientInstance的producerTable为空,把producer保存到producerTable,并返回true。至此,registerOK!!

第二次:创建producer时,没有指定instance name,所以取pid(假设为76052)作为instance name,后面的clientId等于ip+76052,factoryTable有此clientId,直接之前的MQClientInstance。
使用此MQClientInstance去registerProducer,因为MQClientInstance是已存在的,所以MQClientInstance的producerTable不为空,从中取出之前保存的producer,并返回false。至此,register不OK!!抛出异常!!

而如果每次创建producer时,指定instance name呢?
创建producer时,指定instance name(唯一且每次更新),后面的clientId等于ip+InstanceName,因为instance name唯一,所以factoryTable没有此clientId,创建MQClientInstance并写入factoryTable,返回此MQClientInstance。
使用此MQClientInstance去registerProducer,因为MQClientInstance是new出来的,所以MQClientInstance的producerTable为空,把producer保存到producerTable,并返回true。至此,registerOK!!
因为instance name唯一,所以每次都会new MQClientInstance,这样MQClientInstance的producerTable总是为空,总返回true。所以,一直registerOK!!

阅读全文
0 0