Java 为什么我的RabbitMQ频道一直关闭?

Java 为什么我的RabbitMQ频道一直关闭?,java,rabbitmq,Java,Rabbitmq,我正在调试一些使用ApachePOI从Microsoft Office文档中提取数据的Java代码。偶尔,它会遇到一个大文档,当内存不足时POI会崩溃。此时,它尝试将错误发布到RabbitMQ,以便其他组件可以知道此步骤失败并采取适当的操作。但是,当它尝试发布到队列时,会得到一个com.rabbitmq.client.alreadCyclosedException(干净连接关闭;原因:尝试使用封闭通道) 以下是错误处理程序代码: try { //Extraction and indexi

我正在调试一些使用ApachePOI从Microsoft Office文档中提取数据的Java代码。偶尔,它会遇到一个大文档,当内存不足时POI会崩溃。此时,它尝试将错误发布到RabbitMQ,以便其他组件可以知道此步骤失败并采取适当的操作。但是,当它尝试发布到队列时,会得到一个
com.rabbitmq.client.alreadCyclosedException(干净连接关闭;原因:尝试使用封闭通道)

以下是错误处理程序代码:

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());  
}
private void publish(字符串交换、字符串路由、,
AMQP.BasicProperties道具,映射消息)引发异常{
chan.basicPublish(exch、路线、道具、,
toJSONString(message.getBytes());
}
我在try块中找不到任何似乎关闭RabbitMQ通道的代码。是否存在可以隐式关闭通道的情况


EDIT:我应该注意,发布内部的
basicPublish
调用会引发ALREADCYCLOSEDEXCEPTION。

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

  • 试图将邮件发布到不存在的exchange
  • 正在尝试发布设置了立即标志的消息,但该消息没有包含活动使用者集的队列

我将研究在您试图使用的频道上设置Shutdowliner,以使用来发布消息,以捕获关闭事件并查看其原因。

我的另一个原因是我错误地确认了两次消息。这会在第二次确认后导致日志中出现类似这样的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'}
=错误报告===2012年12月11日::09:48:29===
连接,通道1-错误:
{amqp_错误,前提条件_失败,“未知传递标记1”,“basic.ack”}

在我删除重复确认之后,错误消失了,通道不再关闭,AlreadCyclosedException也消失了

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

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

出版者

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

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

vhost“/”中队列“logsquee”的不等价参数“持久”: 收到“true”,但当前为“false”

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

我再次为新队列设置了durable=false,这次我得到了这个错误

vhost“/”中队列“logsque1”的不等价参数“持久”: 收到“false”,但当前为“true”

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

rabbitmqctl list_queues 
我在服务器上看到了两个队列

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

rabbitmqctl stop_app
rabbitmqctl reset
rabbitmqctl start_app

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

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

操作basic.ack导致通道异常预处理失败: 未知的传递标签


显然,有许多原因导致AMQP连接和/或通道突然关闭。在我的例子中,队列上有太多未确认的消息,因为使用者没有指定消息,所以连接每~1分钟就被终止一次。通过将使用者的预回迁计数设置为非零值来限制未确认消息的数量,修复了该问题

channel.basicQos(100); 

结果表明,当内存耗尽时,JVM正在关闭AMQP连接。但是,由于某些原因,当连接关闭时,通道上的关机侦听器没有启动。一旦队列被声明,其属性是不可变的。为什么不删除队列,然后更改队列属性?重新启动整个代理只是为了更改一个队列的属性,这似乎有点单调。您是如何解决此问题的?双确认场景是一个非常好的点。很难看出问题所在。谢谢你的评论,我完全帮助了我。我遇到了同样的问题,这是由于双重NACK。这一点很好。