RabbitMQ Java客户端 - 慢消费者导致连接关闭

时间:2018-02-22 09:36:41

标签: java rabbitmq

我发现了许多" Broken Pipe"或"连接被拒绝"使用RabbitMQ Java驱动程序amqp-client版本5.1.2在我的应用程序中出错。 RabbitMQ服务器版本为3.7.3

要限制收到的消息,我只需将Thread.sleep(2000)循环放入DefaultConsumer autoAck=0channel.basicQos(..)。当然,我可以设置java.net.SocketException,但我需要的不仅仅是"我目前有多少消息"。

但是,此伪代码会导致// register new connection // register new channel / consumer for receiving messages which waits for 2 seconds on each handleDelivery // sleep for 60 seconds (main-thread) and let the consumer do its job // register new channel (for writing)

handleDelivery

另一种情况是,在java.net.SocketException: Broken pipe at java.net.SocketOutputStream.socketWrite0(Native Method) at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:109) at java.net.SocketOutputStream.write(SocketOutputStream.java:153) at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:82) at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:140) at java.io.DataOutputStream.flush(DataOutputStream.java:123) at com.rabbitmq.client.impl.SocketFrameHandler.flush(SocketFrameHandler.java:177) at com.rabbitmq.client.impl.AMQConnection.flush(AMQConnection.java:559) at com.rabbitmq.client.impl.AMQCommand.transmit(AMQCommand.java:127) at com.rabbitmq.client.impl.AMQChannel.quiescingTransmit(AMQChannel.java:447) at com.rabbitmq.client.impl.AMQChannel.quiescingTransmit(AMQChannel.java:429) at com.rabbitmq.client.impl.AMQChannel.quiescingRpc(AMQChannel.java:346) at com.rabbitmq.client.impl.AMQChannel.rpc(AMQChannel.java:337) at com.rabbitmq.client.impl.AMQChannel.privateRpc(AMQChannel.java:277) at com.rabbitmq.client.impl.AMQChannel.exnWrappingRpc(AMQChannel.java:138) at com.rabbitmq.client.impl.ChannelN.open(ChannelN.java:133) at com.rabbitmq.client.impl.ChannelManager.createChannel(ChannelManager.java:176) at com.rabbitmq.client.impl.AMQConnection.createChannel(AMQConnection.java:542) at com.rabbitmq.client.impl.recovery.AutorecoveringConnection.createChannel(AutorecoveringConnection.java:108) at myapp.rabbitmq.RabbitMQPool.registerChannel(RabbitMQPool.java:232) at myapp.rabbitmq.RabbitMQPool.registerChannel(RabbitMQPool.java:200) at myapp.rabbitmq.RabbitMQPool.registerWriteOnlyChannel(RabbitMQPool.java:185) at myapp.rabbitmq.RabbitMQPool.registerWriteOnlyChannel(RabbitMQPool.java:181) at myapp.MyMainClass.start(MyMainClass.java:110) at myapp.MyMainClass.main(MyMainClass.java:46) 中休眠几分钟后,连接被重置/损坏管道/等等。但是让我们专注于伪代码的第一种情况。

这会在创建第二个通道时导致以下堆栈跟踪,第二个通道也使用第一个连接。

handleDelivery

但是,如果我不在每个ConnectionFactory factory = new ConnectionFactory(); factory.setPort(5672); factory.setHost("xxx.xxx.xxx.xxx"); factory.setUsername("user"); factory.setPassword("pass"); factory.setAutomaticRecoveryEnabled(true); factory.setConnectionTimeout(0); Connection connection = factory.newConnection(); 等待2秒,那么创建第二个队列就会很好。为什么呢?

这些是用于创建新连接的参数:

if (!connection.isOpen()) {
    // this fires at the second time when first channel consumes with `Thread.sleep(2000)`
}
channel = connection.createChannel();
channel.queueDeclare(channelName, true, false, false, null);
if (consumer != null) { // only the first time
    DefaultConsumer queueingConsumer = new DefaultConsumer(channel) {
        @Override
        public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) {
            Thread.sleep(2000)
        }
        ... some more @Overrides
    };
    channel.basicConsume(channelName, autoAck, queueingConsumer);
}

构建频道的代码:

3.5.6

RabbitMQ服务器日志不会显示任何错误,也不会抛出其他错误。 RabbitMQ通过局域网连接,我在两种配置中都会将错误重现几十次,结果相同。

我从驱动程序版本5.1.2升级到3.5.6,RabbitMQ服务器(也是新的操作系统)从3.7.3升级到QueueingConsumer,问题就开始了。我想也许DefaultConsumer被弃用了,现在我必须使用$orders = Order::where([ 'kitchen_status' => 1, 'delivery_status' => 0,])->orderBy('update_at','DESC')->paginate(15);

1 个答案:

答案 0 :(得分:0)

我想我找到了解决方案。

将消费线程与Thread.sleep(...)暂停似乎并不是一个好主意。

当我在频道上使用basicCancel(...)时,一切运作良好,不会关闭任何频道,也不会引发异常。