rocketmq官方示例超时报错处理

1.异常信息

版本说明:
mq服务器版本:4.9.2
java客户端:4.9.2

1.1 RemotingTimeoutException: invokeSync call timeout

Caused by: org.apache.rocketmq.remoting.exception.RemotingTimeoutException: invokeSync call timeout
	at org.apache.rocketmq.remoting.netty.NettyRemotingClient.invokeSync(NettyRemotingClient.java:375)
	at org.apache.rocketmq.client.impl.MQClientAPIImpl.getTopicRouteInfoFromNameServer(MQClientAPIImpl.java:1367)
	at org.apache.rocketmq.client.impl.MQClientAPIImpl.getTopicRouteInfoFromNameServer(MQClientAPIImpl.java:1357)
	at org.apache.rocketmq.client.impl.factory.MQClientInstance.updateTopicRouteInfoFromNameServer(MQClientInstance.java:622)
	... 6 more

1.2 RemotingTooMuchRequestException: sendDefaultImpl call timeout

org.apache.rocketmq.remoting.exception.RemotingTooMuchRequestException: sendDefaultImpl call timeout
	at org.apache.rocketmq.client.impl.producer.DefaultMQProducerImpl.sendDefaultImpl(DefaultMQProducerImpl.java:683)
	at org.apache.rocketmq.client.impl.producer.DefaultMQProducerImpl.send(DefaultMQProducerImpl.java:1391)
	at org.apache.rocketmq.client.impl.producer.DefaultMQProducerImpl.send(DefaultMQProducerImpl.java:1335)
	at org.apache.rocketmq.client.producer.DefaultMQProducer.send(DefaultMQProducer.java:336)
	at hh.simple.SyncSendMsg.main(SyncSendMsg.java:35)

2.处理方法

新建自定义MyProducer 类,继承DefaultMQProducer,重写cloneClientConfig,新增实例化MyProducer对象时用到的构造方法
MyProducer 代码如下:
public class MyProducer extends DefaultMQProducer {

    public MyProducer(String producerGroup) {
        super(producerGroup);
    }

    @Override
    public ClientConfig cloneClientConfig() {
        ClientConfig config = super.cloneClientConfig();
        config.setMqClientApiTimeout(super.getMqClientApiTimeout());
        return config;
    }
}

main方法(发送消息的代码如下):

public static void main(String[] args) throws MQClientException {
        DefaultMQProducer producer = new MyProducer("test-group");
        // 设置超时时间
        producer.setMqClientApiTimeout(1000*10);
        producer.setNamesrvAddr("localhost:9876");
        producer.start();
        System.out.printf("SyncProducer Started.%n");
        // topic, tags, body
        Message msg = new Message("test-topic","test-tag", "测试消息1234".getBytes(Charset.forName("utf-8")));
        try {
            // 此处的timeout是等待broker响应信息的时长,设置为10s,以防超时
            SendResult result = producer.send(msg, 1000*10);
            System.out.printf("%s%n", result);
        } catch (RemotingException e) {
            e.printStackTrace();
        } catch (MQBrokerException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        producer.shutdown();
    }

至此重新运行main方法,问题已解决。

3.排查处理过程

根据报错信息,可以定位到报错源码位置:
MQClientAPIImplgetTopicRouteInfoFromNameServer方法的1367行
描述
容易推断出,是因为此方法执行时间超过了给定的timeoutMillis,于是便返回上层,追究参数是从哪里来的:
查找此方法在哪里调用,经排查发现在
MQClientInstanceupdateTopicRouteInfoFromNameServer方法中622行,
那么问题来了,这个clientConfig是从哪里来的呢?请继续往下看
在这里插入图片描述
经排查,这个参数是从MQClientInstance的构造函数传入的

进一步排查,在MQClientManagergetOrCreateMQClientInstance方法的52行调用了上述构造函数并传入由clientConfig.cloneClientConfig()返回的ClientConfig对象,那么这个clientConfig到底是啥,继续往下:

标记一

在这里插入图片描述

进一步排查,在DefaultMQProducerImpl中start方法的201行,原来是defaultMQProducer,应该就是我们new出来的DefaultMQProducer对象,为了证实继续往下:
在这里插入图片描述
看看是哪个地方调用了此构造函数,继续往下:
在这里插入图片描述
果然,就是我们的DefaultMQProducer对象,所以之前的"那么这个clientConfig到底是啥"",答案就是:clientConfigDefaultMQProducer对象。
在这里插入图片描述
那么知道clientConfig就是DefaultMQProducer对象后,再回到标记一处:进入cloneClientConfig方法
在这里插入图片描述

就是重新new了一个ClientConfig对象,把配置参数进行一一赋值,仔细观察这里面没有mqClientApiTimeout这个参数,意思就是除了这里面赋值外的其他参数全部会恢复为ClientConfig类中的参数默认值。
在这里插入图片描述
即:就算我们进行如下操作,在producer中设置了mqClientApiTimeout参数,经过上述操作后,配置也会被清空

DefaultMQProducer producer = new DefaultMQProducer("test-group");
// 设置超时时间
producer.setMqClientApiTimeout(1000*10);

故我们只有重写cloneClientConfig方法,将mqClientApiTimeout参数设置进新的ClientConfig对象中。到此问题得到解决,这就是为什么要继承DefaultMQProducer并重写cloneClientConfig方法的原因。

对于1.2的RemotingTooMuchRequestException: sendDefaultImpl call timeout报错,调用含超时参数的方法即可,具体排查可进入下述send方法逐步查看源码。

// 此处的timeout是等待broker响应信息的时长,设置为10s,以防超时
            SendResult result = producer.send(msg, 1000*10);
            System.out.printf("%s%n", result);

重新运行main方法,超时异常不再出现,若还报超时,可以尝试将超时时间增加。

DefaultMQPushConsumer也可按照上述方法进行设置即可

以下是 RocketMQ 的 pull 示例代码,供您参考: ```java import java.util.List; import org.apache.rocketmq.client.consumer.DefaultMQPullConsumer; import org.apache.rocketmq.client.exception.MQClientException; import org.apache.rocketmq.common.message.MessageExt; import org.apache.rocketmq.common.message.MessageQueue; import org.apache.rocketmq.common.protocol.heartbeat.MessageModel; import org.apache.rocketmq.remoting.exception.RemotingException; public class PullConsumer { public static void main(String[] args) throws MQClientException, RemotingException, InterruptedException { // 实例化消息消费者 DefaultMQPullConsumer consumer = new DefaultMQPullConsumer("example_group_name"); // 设置 NameServer 地址 consumer.setNamesrvAddr("localhost:9876"); // 启动消费者实例 consumer.start(); // 从指定队列中拉取消息 MessageQueue mq = new MessageQueue("TopicTest", "BrokerA", 1); long offset = consumer.fetchConsumeOffset(mq, false); PullResult pullResult = consumer.pull(mq, "*", offset, 32); switch (pullResult.getPullStatus()) { case FOUND: List<MessageExt> msgFoundList = pullResult.getMsgFoundList(); // 处理消息 break; case NO_MATCHED_MSG: // 没有匹配的消息 break; case NO_NEW_MSG: // 没有新的消息 break; case OFFSET_ILLEGAL: // 非法的 offset break; default: break; } // 关闭消费者实例 consumer.shutdown(); } } ``` 在这个示例中,我们创建了一个 DefaultMQPullConsumer 实例,并指定了 NameServer 地址。然后,我们从指定的消息队列中拉取消息,并处理它们。最后,我们关闭了消费者实例。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值