【问题标题】:Why do my RabbitMQ channels keep closing?为什么我的 RabbitMQ 通道一直关闭?
【发布时间】:2012-01-12 17:03:42
【问题描述】:

我正在调试一些使用 Apache POI 从 Microsoft Office 文档中提取数据的 Java 代码。偶尔会遇到大文档,内存不足时POI崩溃。此时,它会尝试将错误发布到 RabbitMQ,以便其他组件可以知道此步骤失败并采取适当的措施。但是,当它尝试发布到队列时,它会得到一个com.rabbitmq.client.AlreadyClosedException (clean connection shutdown; reason: Attempt to use closed channel)

这是错误处理程序代码:

try {
    //Extraction and indexing code
}
catch(Throwable t) {
    // Something went wrong! We'll publish the error and then move on with
    // our lives
    System.out.println("Error received when indexing message: ");
    t.printStackTrace();
    System.out.println();
    String error = PrintExc.format(t);
    message.put("error", error);

    if(mime == null) {
        mime = "application/vnd.unknown";
    }

    message.put("mime", mime);
    publish("IndexFailure", "", MessageProperties.PERSISTENT_BASIC, message);
}

为了完整起见,这里是发布方法:

private void publish(String exch, String route, 
    AMQP.BasicProperties props, Map<String, Object> message) throws Exception{
    chan.basicPublish(exch, route, props, 
        JSONValue.toJSONString(message).getBytes());  
}

我在 try 块中找不到任何似乎关闭 RabbitMQ 通道的代码。有没有可以隐式关闭通道的情况?

编辑:我应该注意,AlreadyClosedException 是由发布内部的basicPublish 调用引发的。

【问题讨论】:

  • 你是如何解决这个问题的?

标签: java rabbitmq


【解决方案1】:

AMQP 通道因通道错误而关闭。可能导致通道错误的两种常见情况:

  • 试图将消息发布到不存在的交换器
  • 尝试发布一条设置了立即标志但没有包含活动消费者集的队列的消息

我会考虑在您尝试使用addShutdownListener() 发布消息的频道上设置一个 ShutdownListener 以捕获关闭事件并查看导致它的原因。

【讨论】:

  • 原来AMQP连接在内存不足时被JVM关闭了。但是,由于某种原因,连接关闭时通道上的关闭侦听器没有触发。
【解决方案2】:

我的另一个原因是我错误地确认了两次消息。这会在第二次确认后导致日志中出现这样的 RabbitMQ 错误。

=ERROR REPORT==== 11-Dec-2012::09:48:29 ===
connection <0.6792.0>, channel 1 - error:
{amqp_error,precondition_failed,"unknown delivery tag 1",'basic.ack'}

删除重复确认后,错误消失了,通道不再关闭,AlreadyClosedException 也消失了。

【讨论】:

  • 这种双重确认方案是一个非常好的观点。很难看出问题。感谢您的评论,我完全帮助了我。
  • 我遇到了同样的问题,这是由于双重 NACK。好点在这里。
【解决方案3】:

我想为将要搜索此主题的其他用户添加此信息

接收通道关闭异常的另一个可能原因是发布者和消费者使用不同的队列声明/设置访问通道/队列时

出版商

channel.queueDeclare("task_queue", durable, false, false, null);

工人

channel.queueDeclare("task_queue", false, false, false, null);

来自 RabbitMQ 站点

RabbitMQ doesn't allow you to redefine an existing queue with different parameters and will return an error to any program that tries to do that

【讨论】:

    【解决方案4】:

    显然,AMQP 连接和/或通道突然关闭的原因有很多。在我的情况下,队列中有太多未确认的消息,因为消费者没有指定prefetch_count,所以连接每隔约 1 分钟就会终止一次。通过将消费者的预取计数设置为非零值来限制未确认消息的数量可以解决问题。

    channel.basicQos(100); 
    

    【讨论】:

      【解决方案5】:

      我也有这个问题。我的案例的原因是,首先我使用durable = false 构建了队列,并且在日志文件中,当我将durable 切换为true 时出现了以下错误消息:

      “虚拟主机'/'中队列'logsQueue'的不等价参数'durable': 收到“真”但当前为“假””

      然后,我更改了队列的名称,它对我有用。我假设 RabbitMQ 服务器将已构建队列的记录保存在某处,它无法将状态从持久更改为非持久,反之亦然。

      我再次为新队列设置了耐用=false,这次我收到了这个错误

      “vhost '/' 中队列 'logsQueue1' 的不等价参数 'durable': 收到“假”但当前为“真””

      我的假设是正确的。当我通过以下方式列出rabbitMQ服务器中的队列时:

      rabbitmqctl list_queues 
      

      我在服务器中看到了两个队列。

      总而言之,2个解决方案是: 1.重命名队列的名称不是很好的解决方案 2.通过以下方式重置rabbitMQ:

      rabbitmqctl stop_app
      rabbitmqctl reset
      rabbitmqctl start_app
      

      【讨论】:

      • 一旦队列被声明,它的属性是不可变的。为什么不直接删除队列然后更改队列属性?重新启动整个代理只是为了改变一个队列的属性似乎有点激烈
      【解决方案6】:

      对于那些想知道为什么他们的消费渠道关闭的人,请检查您是否多次尝试确认或拒绝交付。

      在 rabbitmq 日志中,您会看到如下消息:

      操作basic.ack导致通道异常precondition_failed: 未知的交货标签...

      【讨论】:

        猜你喜欢
        • 2022-12-05
        • 1970-01-01
        • 1970-01-01
        • 2015-11-05
        • 2020-08-17
        • 2019-06-27
        • 2018-01-29
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多