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