1

我有 1 个 RabbitMQ 连接、10K 发布通道、10K 消费通道和 100 个线程。所有通道都处于使用排他队列和外部同步的快速发布/消费“循环”中;不可能在一个通道上同时发生发布、消费或关闭。在 100 个线程上同时关闭通道会导致前 100 个通道中的每个通道延迟 2.5 秒。所有后续的关闭都在不到 0.5 秒内处理完毕。如果我将其增加到 20K+20K 通道,则最初的 100 个通道需要 5 秒才能关闭。30K + 30K 每​​个需要 10 秒,我们几乎处于连接的最大通道。同样,如果我将线程数减少到 50,那么前 50 个通道会慢慢关闭。

让我重申一下……对于 30K+30K 通道,前 100 个通道需要 10 秒才能使用 100 个并发线程关闭。剩下的 59,900 个每个用时不到 0.5 秒。我的感觉是这里正在进行一些时髦的连接范围的同步/继续。同时在 100 个线程上使用 100 个通道关闭请求来建立连接,并且它会退缩。无论导致初始痉挛的原因似乎都不会影响随后的关闭操作,并且一切都很好地游泳。

我尝试增加连接数量以减轻压力。这当然适用于可预测的结果。由于 30K+30K 连接均匀分布在 2 个连接上,最初的 100 个通道关闭延迟从 10 秒减半至 5 秒。使用 10 个连接,与随后的 59,900 个通道关闭相比,延迟几乎不可察觉。跳转到 50K+50K 通道(我们可以使用 10 个连接但不是 1 个连接,因为通道最大)并且延迟开始再次蔓延。

我对这种方法的担忧是 1) 由于 i/o 资源开销,文档中不鼓励使用多个连接,并且 2) 我的应用程序不清楚如何明智地预测每个连接的最佳通道数。如果每个连接的通道数有软限制,为什么它没有在 api 中记录或提供?如果我必须管理多个连接并以稳健的方式跨这些连接分配通道,我觉得我正在做客户端库的工作!

我已经尝试通过不等待来自 RabbitMQ 服务器的通道关闭确认来修改客户端库。这就像一个魅力。通道立即关闭,客户端没有延迟,并在服务器上确认为关闭。八小时后,由于客户端库内部的通道资源没有被释放,我的堆空间不足。我也没有设法隔离延迟的来源......它是在客户端库中还是在服务器本身中?为了进一步取得进展,我需要跟踪有线协议。我想我偏离了这种方法!

问题:

在进行应用程序更改之前,我想知道这是否是 Java 客户端的一个已知问题?是否有比多连接和应用程序级通道管理更好的解决方法?在实践中,我的实际应用程序每个进程使用大约 20K 通道,我认为这并不过分,而且消息吞吐量实际上非常轻,因为我更多地利用 RabbitMQ 进行路由。我什至可以忍受延误,但它们已经很明显了。我可以重构以使用更少的频道,但随后我将共享频道,并且要么必须同步它们的使用,要么忽略文档指南。但是,错误处理范例使这很麻烦;任何通道错误都会导致其终止,因此很难隔离错误,防止它们渗透并以稳健的方式恢复。

细节:

RabbitMQ 服务器 3.1.5,Java amqp-client 3.1.5。还在同一个测试工具中尝试了 3.1.4、3.1.3,并看到了我认为在 3.0 和生产应用程序之前的行为完全相同的行为。

我的测试工具是独立的,但在这里发布有点迟钝。我创建了 10K 测试客户端,每个测试客户端都创建一个独占队列并运行一个连续的发布-消费-发布-消费循环。发布者和消费者都有自己的渠道。我将 channel.basicConsume 与 DefaultConsumers 和默认的消费者执行程序服务一起使用。还使用了我自己的 Java 执行器服务,它似乎与默认实现相同,具有不同数量的线程,没有明显的效果。

handleDelivery 中使用的消息通过 java.concurrent 固定线程池生成一个新的发布任务,因此消费者线程不会被绑定或用于任何通道操作。通道关闭是同步的,因此它不能与发布同时发生。但是,在处理关闭时没有什么能阻止消费的发生——消费者不受我的控制。

感谢您的任何指点!

4

0 回答 0