![如何在不升级服务器的情况下防止管理插件中陈旧/错误的 RabbitMQ 连接对象激增?](https://linux22.com/image/623490/%E5%A6%82%E4%BD%95%E5%9C%A8%E4%B8%8D%E5%8D%87%E7%BA%A7%E6%9C%8D%E5%8A%A1%E5%99%A8%E7%9A%84%E6%83%85%E5%86%B5%E4%B8%8B%E9%98%B2%E6%AD%A2%E7%AE%A1%E7%90%86%E6%8F%92%E4%BB%B6%E4%B8%AD%E9%99%88%E6%97%A7%2F%E9%94%99%E8%AF%AF%E7%9A%84%20RabbitMQ%20%E8%BF%9E%E6%8E%A5%E5%AF%B9%E8%B1%A1%E6%BF%80%E5%A2%9E%EF%BC%9F.png)
语境:
我们使用 RabbitMQ 2.8.4 HA 集群在中型(数百到数千台服务器)数据中心内进行消息传递。消息传递功能对于我们的应用至关重要。
我们使用 C 客户端 API 进行 AMQP/RabbitMQ 操作,并使用 HTTP API 进行 RabbitMQ 管理插件定期监控队列状态并根据大小/吞吐量/等发送警报。
从客户端到消息服务器允许的唯一端口/连接是 AMQP 端口和管理 API 的 HTTP。
在不久的将来,管理层已决定,消息传递集群的停机(这意味着应用程序的某些请求部分将停机)是不可接受的。几个月后,这种情况将有可能出现,但在此之前,出于销售方面的考虑,我们无法维护消息传递系统。这很糟糕,但我们(基础设施/开发运维人员)没有权利做出这些决定。
问题:
有一段时间,我们一直受到这个问题。在连接风暴之后,或者在新客户端频繁连接和使用 AMQP 系统的很长一段时间内,RabbitMQ 管理 API 会显示数十万个被列为“正在运行”但实际上已不存在的连接。netstat
,lsof
并且其他诊断证明这些连接对应的套接字在客户端上未打开;管理 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_keepalive
和exit_on_close
TCP 设置。这些值的组合都无法解决问题。 - 我们编写了一个脚本,该脚本迭代 JSON API 连接列表返回的所有连接,并为每个打开时间超过使用时间的连接发送 DELETE。所有此类请求都会遇到 500 服务器错误,如上面链接的 SO 问题中所述。
答案1
您不断定期重新启动一切。
另一个选择是将修复程序从 3.x 反向移植到当前版本,但如果不允许升级,您可能也不会被允许这样做。而且这几乎肯定会比升级工作量大得多,特别是如果 RabbitMQ 代码已经进行了重大重构。
直到你可以改变政治在这种情况下,这些都是你的选择。