You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

RabbitMQ消费消息后报未知delivery tag错误,通道持续创建求助

问题分析与解决

错误现象

每条消息消费后触发通道关闭错误,通道数量持续增长,消息消费处理正常但资源消耗异常:

Channel shutdown: channel error; protocol method: #method<channel.close>(reply-code=406, reply-text=PRECONDITION_FAILED - unknown delivery tag 1, class-id=60, method-id=80)
o.s.a.r.l.SimpleMessageListenerContainer - : Restarting Consumer@3d5a462b: tags=[{amq.ctag-zGA1v36aEmXxnG7bqBUcdg=asstMgmt.queue}], channel=Cached Rabbit Channel: AMQChannel(amqp://mqadmin@xx:xx:xx:xx:5672/assetmgmt,1165), conn: Proxy@5c87dd9e Shared Rabbit Connection: SimpleConnection@2ec6c89 [delegate=amqp://mqadmin@@xx:xx:xx:xx:5672/assetmgmt, localPort= port], acknowledgeMode=AUTO local queue size=0

核心问题原因

  1. 手动ACK与容器自动ACK冲突
    从日志可见容器使用的是acknowledgeMode=AUTO模式,容器会自动处理消息确认,但你的代码中手动调用了basicAck/basicReject。这会导致RabbitMQ收到重复的确认请求:容器已经将delivery tag标记为已处理,手动再次操作时tag失效,触发unknown delivery tag错误。通道因错误被关闭后,容器只能创建新通道维持消费,最终导致通道数量暴增。

  2. 消费代码存在重复确认逻辑
    在msgType为空的分支中,执行channel.basicReject后没有终止方法,后续代码依然会执行channel.basicAck,进一步加剧重复确认问题。

  3. 容器工厂冗余配置
    在SimpleRabbitListenerContainerFactory中创建的RabbitTemplate未被容器使用,属于无效配置,浪费资源。

解决方案

方案一:切换为手动确认模式(推荐)

修改容器工厂配置,启用手动确认模式,让代码完全控制消息确认逻辑:

@Bean
public SimpleRabbitListenerContainerFactory assetContainerFactory(
        @Qualifier("connectionFactory") ConnectionFactory connectionFactory
) {
    SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
    factory.setConnectionFactory(connectionFactory);
    factory.setConcurrentConsumers(3);
    factory.setMaxConcurrentConsumers(6);
    factory.setDefaultRequeueRejected(false);
    // 启用手动确认模式
    factory.setAcknowledgeMode(AcknowledgeMode.MANUAL);
    // 移除无用的RabbitTemplate配置
    return factory;
}

同时修复消费代码的重复确认问题,在执行拒绝操作后终止方法:

@RabbitListener(admin = "amqpAssetMgmtAdmin" ,queues = "${asstMgmt.queue.name}",
              containerFactory = "assetContainerFactory")
public void loadAssetMgmtData(Message msg,Channel channel) throws IOException {
    long tag =0;
    try {
        UDDAO dao = new UDDAO();
        dao.setAssetMgmtRabbitTemplate(assetMgmtRabbitTemplate);
        Map<String, Object> headers = msg.getMessageProperties().getHeaders();
        String msgType = (String) headers.get("type");
        String payload = new String(msg.getBody());
        tag = msg.getMessageProperties().getDeliveryTag();
        
        if(msgType == null || msgType.isEmpty()){
            log.error("Got message with empty message type, rejecting the message");
            channel.basicReject(tag, false);
            // 添加return避免后续执行basicAck
            return;
        }
        
        //Process the message
        channel.basicAck(tag, false);

    }  catch (JDBCConnectionException e) {
        log.error("DB exception so requeueing the message");
        log.error(e.getMessage());
        if(tag>0)
            channel.basicReject(tag, true);

    }catch (Exception e) {
        if(msg.getMessageProperties().getRedelivered()){
            log.error("Internal server error occurred. rejecting without requeueing ", e);
            if(tag>0)
                channel.basicReject(tag, false);
        }else{
            if(tag>0)
                channel.basicReject(tag, true);
            log.error("Internal server error occurred. rejecting and requeuing ", e);
        }
    }
}

方案二:保留自动确认,移除手动确认代码

如果不需要精细控制确认逻辑,直接删除代码中所有channel.basicAck和channel.basicReject调用,让容器自动处理确认。可以通过factory.setDefaultRequeueRejected(false)配置全局是否重入队,或在@RabbitListener中通过requeueRejected属性单独配置。

额外优化

删除两个SimpleRabbitListenerContainerFactory中冗余的RabbitTemplate创建代码,减少不必要的资源消耗。

内容的提问来源于stack exchange,提问作者mrtCherry

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 21:17:34