Azure 中 node.js RabbitMQ 消费者上的 ECONNRESET

ECONNRESET on node.js RabbitMQ consumer in Azure

我已经研究这个问题好几天了,它让我完全难住了。我们有一个基于 node.js 的 rabbitmq 消费者,它已经 运行 在本地使用了一年多,没有任何问题。最近我们将我们的应用程序部署到 Azure,并将 node.js 组件部署到基于 window 的 PAAS 工作者角色。我们使用 square mo amqp-lib (https://github.com/squaremo/amqp.node) 作为我们的客户端库来接收来自 RabbitMQ 的消息。该角色开始正常,处理请求没有问题,但会定期回收。

检查已部署 VM 上 C:\resources 中的 WaHostBootstrapper 日志显示如下:

[00001180:00001548, 2015/06/09, 10:01:17.385, INFO ] Getting status from client RemoteAccessAgent.exe (2816).
[00001180:00001548, 2015/06/09, 10:01:17.385, INFO ] Client reported status 0.
[00001180:00001548, 2015/06/09, 10:01:17.385, INFO ] Getting status from client WaWorkerHost.exe (1380).
[00001180:00001548, 2015/06/09, 10:01:17.385, INFO ] Client reported status 3.
[00001180:00003288, 2015/06/09, 10:01:17.385, INFO ] Sending shutdown notification to client RemoteAccessAgent.exe (2816).
[00001180:00003288, 2015/06/09, 10:01:17.416, ERROR] <- CRuntimeClient::OnRoleShutdownCallback(0x0000000000331890) =0x800706be
[00001180:00003288, 2015/06/09, 10:01:17.416, INFO ] Sending shutdown notification to client WaWorkerHost.exe (1380).

VM 上的任何其他事件日志中没有其他值得注意的内容。 我修改了角色模型启动任务以将所有控制台输出记录到一个文件中,该文件未显示任何错误。为了更清楚地了解正在发生的事情,我使用 $ENV:NODE_DEBUG = "net,http" 启用了 http 和 net 模块的 NODE_DEBUG,然后直接 运行 启动任务从电源外壳。经过一段时间完美处理请求后,我得到以下信息:

NET: 3720 destroy undefined
NET: 3720 destroy
NET: 3720 close
NET: 3720 close handle
NET: 3720 emit close
NET: 3720 afterWrite 0 { domain: null, bytes: 21, oncomplete: [Function: afterWrite] }
NET: 3720 afterWrite call cb
NET: 3720 afterWrite 0 { domain: null, bytes: 8, oncomplete: [Function: afterWrite] }
NET: 3720 afterWrite call cb
NET: 3720 onread ECONNRESET undefined undefined NaN
NET: 3720 error ECONNRESET
NET: 3720 destroy
NET: 3720 close
NET: 3720 close handle

rabbitMQ 服务器有以下日志条目:

=WARNING REPORT==== 13-Mar-2015::17:48:39 ===
closing AMQP connection <0.7072.1> (137.116.194.234:1307 -> 10.140.42.79:5672):
connection_closed_abruptly

看到这个之后,我很清楚消费者和服务器之间的某些东西正在关闭连接,导致节点进程退出(我们没有监听来自 AMQP 连接的错误事件)反过来导致角色回收。

我已经成功地通过使用 TCPView (sysInternals) 手动关闭与 rabbit 服务器的连接来复制它。

因为这只发生在部署到 Azure 时,我猜想一定有一些 Azure 基础设施以不正当的方式关闭了这个连接,从而导致了这个问题。但是什么?

我想我已经解决了这个问题!由于缺少合适的错误消息和 Azure 负载均衡器的不可见性,这非常棘手。事实证明这是一个非常简单的修复,但一点也不明显(直到你知道它,然后它才有意义)。

简答

Azure 负载均衡器发现空闲连接并将其终止。

修复

在客户端和 rabbitmq 之间的 运行 长连接上启用心跳。您可以通过将 ?heartbeat=5 附加到服务器连接字符串的末尾来轻松完成此操作:

amqp.connect('amqp://' + server + "?heartbeat=5", function(err, conn) {
...
}

资源

Azure 负载平衡后台和超时:http://blogs.msdn.com/b/avkashchauhan/archive/2011/11/12/windows-azure-load-balancer-timeout-details.aspx

amqp-lib 心跳:http://www.squaremobius.net/amqp.node/doc/channel_api.html