RocketMQ消費重試問題

異常現象

監控日誌展示如下:

[2019-10-30 14:31:23.339 INFO ] [ConsumeMessageThread_7] (com.xxx.service.mq.MQConsumerService:93) - 消費消息:msgId=0A064C3E000179C63692734B339201B0 topic=topic_xxx tag=yyy reconsumeTimes=12

reconsumeTimes 代表消費重試次數。
同時日誌中頻繁顯示同一條msgId。

排查原因

通過debug發現在執行業務代碼時,拋出的異常被mq捕獲,如下:

org.apache.rocketmq.client.impl.consumer.ConsumeMessageOrderlyService.ConsumeRequest#run
try {
    this.processQueue.getLockConsume().lock();
    if (this.processQueue.isDropped()) {
        log.warn("consumeMessage, the message queue not be able to consume, because it's dropped. {}",
            this.messageQueue);
        break;
    }

    status = messageListener.consumeMessage(Collections.unmodifiableList(msgs), context);
} catch (Throwable e) {
    log.warn("consumeMessage exception: {} Group: {} Msgs: {} MQ: {}", //
        RemotingHelper.exceptionSimpleDesc(e), //
        ConsumeMessageOrderlyService.this.consumerGroup, //
        msgs, //
        messageQueue);
    hasException = true;
} finally {
    this.processQueue.getLockConsume().unlock();
}

if (null == status) {
    status = ConsumeOrderlyStatus.SUSPEND_CURRENT_QUEUE_A_MOMENT;
}

當發生異常時messageListener.consumeMessage方法的返回值爲null
當status爲null時,status會被賦值爲ConsumeOrderlyStatus.SUSPEND_CURRENT_QUEUE_A_MOMENT狀態(即隔一段時間後重試)。

上文造成消息重試的異常信息如下

java.lang.NoSuchMethodError: com.soaclient.dto.xxx.LogQueryDto.getMqTypeIn()Ljava/util/List;

由於該異常爲Error級別,而業務代碼異常捕獲級別爲Exception,導致異常沒有被捕獲。

改進方法

1、修改業務代碼異常
2、修改異常捕獲級別爲throwable級別,並輸出異常日誌
3、增加重試次數限制,當大於一定次數時,則不再重試。
如果不加重試,針對順序消費的情況,可能會出現消費被阻塞的情況。
而無序消費,默認最多重試16次。

題外話

當爲無序消費時,代碼如下:

try {
    ConsumeMessageConcurrentlyService.this.resetRetryTopic(msgs);
    if (msgs != null && !msgs.isEmpty()) {
        for (MessageExt msg : msgs) {
            MessageAccessor.setConsumeStartTimeStamp(msg, String.valueOf(System.currentTimeMillis()));
        }
    }
    status = listener.consumeMessage(Collections.unmodifiableList(msgs), context);
} catch (Throwable e) {
    log.warn("consumeMessage exception: {} Group: {} Msgs: {} MQ: {}",
        RemotingHelper.exceptionSimpleDesc(e), //
        ConsumeMessageConcurrentlyService.this.consumerGroup,
        msgs,
        messageQueue);
    hasException = true;
}

if (null == status) {
    log.warn("consumeMessage return null, Group: {} Msgs: {} MQ: {}",
        ConsumeMessageConcurrentlyService.this.consumerGroup,
        msgs,
        messageQueue);
    status = ConsumeConcurrentlyStatus.RECONSUME_LATER;
}

參考

消息隊列 MQ > 高級特性 > 消息重試
https://help.aliyun.com/document_detail/43490.html?spm=a2c4g.11186623.6.555.35b96c99oNQKPt

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章