如何在不升级服务器的情况下防止管理插件中陈旧/错误的 RabbitMQ 连接对象激增?

如何在不升级服务器的情况下防止管理插件中陈旧/错误的 RabbitMQ 连接对象激增?

语境:

我们使用 RabbitMQ 2.8.4 HA 集群在中型(数百到数千台服务器)数据中心内进行消息传递。消息传递功能对于我们的应用至关重要。

我们使用 C 客户端 API 进行 AMQP/RabbitMQ 操作,并使用 HTTP API 进行 RabbitMQ 管理插件定期监控队列状态并根据大小/吞吐量/等发送警报。

从客户端到消息服务器允许的唯一端口/连接是 AMQP 端口和管理 API 的 HTTP。

在不久的将来,管理层已决定,消息传递集群的停机(这意味着应用程序的某些请求部分将停机)是不可接受的。几个月后,这种情况将有可能出现,但在此之前,出于销售方面的考虑,我们无法维护消息传递系统。这很糟糕,但我们(基础设施/开发运维人员)没有权利做出这些决定。

问题:

有一段时间,我们一直受到这个问题。在连接风暴之后,或者在新客户端频繁连接和使用 AMQP 系统的很长一段时间内,RabbitMQ 管理 API 会显示数十万个被列为“正在运行”但实际上已不存在的连接。netstatlsof并且其他诊断证明这些连接对应的套接字在客户端上未打开;管理 API 只是由于某种原因无法修剪条目。rabbitmqctl list_connections有时会显示一些不存在的连接仍然打开,但它显示的连接总是比管理 API 少很多,并且它的“陈旧”检测似乎比 API 更好,并且它最终会从其列表中清除错误的连接。

当我们尝试通过 Web UI 删除其中一个“错误”连接时,页面不会响应我们按下的“删除”按钮,并且该连接仍保留在列表中。当我们尝试通过在 JSON API 中发送 DELETE 来删除它时,我们会收到 500 服务器错误,表明该连接无效,因此无法删除(正如上面链接的 SO 问题中所述)。

这些不存在的连接对象长期积累之后,会发生三件坏事,无特定顺序:

  • RabbitMQ 服务器出现大量内存峰值(这些峰值毫无征兆地出现;它们与管理 API 中的缓慢连接蠕变无关,尽管其内存消耗会随着时间的推移而缓慢增长)。这通常会导致崩溃。
  • 管理 API 停止响应请求(API 客户端超时)。
  • RabbitMQ 服务器本身开始偶尔拒绝未使用 HTTP/管理 API 执行任何操作的 AMQP 客户端的连接。

如果该问题开始破坏我们的应用程序,我们必须做以下两件事之一:* 重新启动整个消息传递集群,这很糟糕,因为它会导致短暂的停机,也很糟糕,因为在此过程中可能会丢失消息。 * 重新启动并清除管理 API 的数据库,这很糟糕,因为我们无法使用管理 API,更糟糕的是,它经常会破坏管理 API,以至于它无法再次正常启动,直到我们重新启动整个集群,如第一点所述。

大多数遇到类似问题的人都通过升级到 RabbitMQ 3.* 来解决这些问题。我们既没有时间,也没有权限,也没有停机授权来开展这样的项目。即使我们因为这个问题重新启动集群时会遇到几分钟的定期停机,我们也没有权限升级。这纯粹是政治限制,但却是一个不幸的现实。

问题:

鉴于我们无法在不久的将来升级 RabbitMQ,并且我们需要继续使用管理 API,我们如何解决导致消息传递集群故障的持久、陈旧连接问题?

我们有能力开发新的/不同的客户端代码,并在消息传递服务器上运行作业,但我们没有能力在任何客户端机器上rabbitmqctl本地使用或通过它们使用。ssh

我们尝试过的方法:

  • 我们尝试切换 AMQP 客户端库,希望有更好的客户端能够自行清理,不会留下陈旧的连接,但无济于事。问题仍然存在。
  • 我们尝试在 RabbitMQ 服务器上调整tcp_keepaliveexit_on_closeTCP 设置。这些值的组合都无法解决问题。
  • 我们编写了一个脚本,该脚本迭代 JSON API 连接列表返回的所有连接,并为每个打开时间超过使用时间的连接发送 DELETE。所有此类请求都会遇到 500 服务器错误,如上面链接的 SO 问题中所述。

答案1

您不断定期重新启动一切。

另一个选择是将修复程序从 3.x 反向移植到当前版本,但如果不允许升级,您可能也不会被允许这样做。而且这几乎肯定会比升级工作量大得多,特别是如果 RabbitMQ 代码已经进行了重大重构。

直到你可以改变政治在这种情况下,这些都是你的选择。

相关内容