我有1个RabbitMQ连接,10K发布频道,10K消费频道和100个线程。所有通道都使用独占队列和外部同步快速发布/使用“循环”;不可能在频道上同时发布,消费或关闭。在100个线程上同时关闭通道会产生一个 前100个通道中的每个通道延迟2.5秒。所有后续闭合都在不到0.5秒的时间内完成。如果我将其提升到20K + 20K通道,则每个通道需要5秒才能关闭。 30K + 30K每个需要10秒,我们几乎都是连接的最大通道。同样,如果我将线程数减少到50,那么它就是前50个缓慢关闭的通道。
让我重申一下...... 使用30K + 30K通道,前100个通道需要10秒才能使用100个同步线程关闭。剩余的59,900每个花费不到0.5秒。我的感觉是这里有一些时髦的连接范围的同步/继续。在100个线程上同时进行100个通道关闭请求的连接,并且它可以阻止。无论是什么原因,最初的痉挛似乎都不会影响随后的近距离手术,一切都很顺利。
我已经尝试增加连接数量以减轻压力。这当然适用于可预测的结果。通过2个连接均匀分布30K + 30K连接,最初的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测试客户端,每个客户端创建一个独占队列并运行一个连续的publish-consume-publish-consume循环。出版商和消费者都有自己的渠道。我正在使用带有DefaultConsumers的channel.basicConsume和一个默认的使用者执行器服务。还使用了我自己的Java执行器服务,它似乎与默认实现相同,具有不同数量的线程,没有明显的效果。
handleDelivery中消耗的消息通过java.concurrent固定线程池生成新的发布任务,因此消费者线程不会被束缚或在任何通道操作中使用。频道关闭是同步的,因此它不能与发布同时发生。然而,正在处理关闭时没有什么可以阻止消费的发生 - 消费者不受我的控制。
感谢您的任何指示!