我对 RabbitMQ 比较陌生,发现它非常方便和快捷,我使用 ruby + bunny gem 将它用于通信小对象。
现在我正在尝试传递大约 10~20MB 的对象以进行交换,并将其扇出给它的订阅者。
看起来效果很好,但是使用 RabbitMQ 作为发布者是一个好习惯吗?或者我应该对 RabbitMQ 使用一些猜想吗?
您不应该通过 AMQP 发送文件。
消息队列不是数据库。具体来说,RabbitMQ 的构建并没有考虑将大对象存储在队列中,因为消息不应该很大。
想想现实世界——多年来的邮政服务(不再需要那么多),都针对处理信件进行了优化。如果你的信太胖(太重),他们会收取相当高的额外邮费。大消息移动和破坏系统的成本更高。此外,您的邮箱不会保存大邮件 - 它们会留在其他地方 - 无论是在单独的包裹投递中还是在您的前门(它们有时会丢失)。
消息队列也是如此。消息通常包含一小段数据,描述在您的应用程序中发生的事件或其他有意义的事情。通常,一条消息所传达的数据可以在 100kB 或更少的时间内进行通信。
正如我在这个答案中提到的,AMQP 协议(它是 RabbitMQ 的基础)是一个相当健谈的协议。它要求将大消息分成不超过 131kB 的多个段。这会给大型文件传输增加大量开销,尤其是与其他文件传输机制(例如 FTP、HTTP)相比时。
更重要的是,对于性能而言,消息在队列中可用之前必须由代理完全处理,并且在完成此操作时它会占用代理上的 RAM。将文件放入代理可能适用于一个客户端和一个代理,但在尝试横向扩展时会很快中断。最后,在传输文件时通常需要压缩——HTTP 自动支持 gzip 压缩,而 AMQP 不支持。
你该怎么办? 在面向消息的应用程序中,发送包含指向较大数据文件的资源定位符(例如 URL)的消息是很常见的,然后通过适当的方式访问该文件。
如果它有效并且不会给您带来任何问题,那就太好了。我建议将每个对象转换为字节数组可能会有时间成本。显然,消费者方面的情况也正好相反。由于每个对象都很大,可能需要考虑,除非速度不是您的主要目标。有必要寄这么大的东西吗?
发送大对象的一个大问题是它们会阻塞整个连接,因此如果您在同一个连接上发布多个频道,他们将不得不等待每个连接完成发送这个大对象。