由于频道不是线程安全的,我可以在发布之前同步频道实例,也可以在每次需要时创建一个频道并关闭它。
但在我看来,由于锁定或创建和破坏渠道的成本,他们都没有表现出色。
那么我应该如何使用高tps向rabbitmq发布消息?对此有何好的准备?
答案 0 :(得分:0)
你应该使用游泳池。
例如,使用Apache's Generic Object Pool并提供打开,关闭和检查连接的实现。当您需要发布消息时,您从池中借用一个频道,使用它并返回它。
答案 1 :(得分:0)
所以,首先要做的事情。 通道不是连接。在RabbitMQ中,通道与应用程序会话相同,而连接表示与服务器的基础TCP会话。 This answer很好地解释了一些。
TCP会话的创建成本很高,因此它们往往具有超出任何特定工作线程生命周期的生命周期。频道的创建非常便宜 - 所有服务器都会为您的频道标识符分配一个整数,并且您有一个新的频道。
RabbitMQ上的大多数操作在失败时都关闭了一个频道。这样做是因为没有这样做的实际后果。他们会关闭底层连接,这会给应用程序带来很多问题。
设计指导
如果您真的需要进行大量处理,则池化适用于连接。关于如何做到这一点的讨论实际上超出了我在简短答案中提供的内容。
渠道的汇总绝对不合适。通道是一种轻量级构造,旨在具有瞬态寿命。如果它持续超过一两个发布,那很好。但是你应该期望每次尝试操作时都有可能失败并关闭通道。这不会关闭底层连接,但必须重新建立新的通道才能对代理执行任何操作。
消费者的生命周期与渠道息息相关。当频道关闭时,附加的消费者也会关闭。设计您的消费者对象(工作线程),以便在发生这种情况时获得连接并创建新频道,然后重新订阅。
避免跨线程共享频道。一个帖子=一个频道。
虽然我对Java客户端没有任何特殊经验,但我不相信锁定是必要的,我当然希望实现不会做任何事情。使频道不是轻量级的。
如果您正在编写自己的协议实现库(不是必需的,但如果您需要细粒度控制也不是一个坏主意),请分配一个线程来管理每个connection
。不要并行读取和写入TCP套接字,否则您将破坏协议。
关于Java客户端,我认为您可以假设通道操作(读取和写入等) NOT 是线程安全的,这就是您希望坚持一个线程的原因/一个渠道范式。我认为您可以假设创建通道(连接操作)是线程安全的。