队列 vs 非阻塞I/O

5
所以,我们正在设计一种新的微服务架构。其中最大的挑战之一是内部通信。对于需要响应的通信,我们使用REST API。但是对于只想中继信息的服务来说,这种API处理是不必要的开销。
一种方法是使用队列。Service1将信息推入队列,Service2可以从队列中消费。因此,Service1无需等待(不像API调用)。 (如果在处理信息时出现任何错误,则Service2可以通过回调URL向Service1发送通知,或以其他方式发送通知;这在此时不是问题[1])。
现在有两个选项,一个是RabbitMQ。另一个是AWS SQS。使用RabbitMQ,我需要担心服务器设置和所有其他方面(虽然可以实现,但希望避免)。因此,在进行了SQS的POC之后,它似乎是一个不错的选择,但问题是SQS在内部使用REST API与AWS服务器通信,在两个点上(Service1在推送时,Service2在消费时),都会有开销。因此,现在我在考虑为什么不使用NodeJS进行操作,Service1将向Service2发送信息。 Service2将立即响应,确认已收到信息,如果有任何错误则[1]。
现在我可以总结一下优缺点:
RabbitMQ
- 易于实现 - 在接收者不可用的情况下,发送者不必担心重试。 - 服务器设置成本+维护(+调整)
SQS
- 最容易实现 - 定价 - 不断轮询消息 - 推/收时有开销
非阻塞API
- 无需第三方媒介进行通信 - Service1必须管理重试机制 - 相对于SQS,开销较小 - 信息将在处理之前保存在内存中
因此,我的问题是,使用非阻塞API是否是一个好主意?或者哪种方法更好,从而使系统具有可伸缩性。
编辑 - 可以使用PubNub或Pusher这样的PubSub提供程序代替队列吗?

问题中存在一些错误的前提。SQS API在技术上并不是一个REST API,即使它是,我也不明白为什么会有反对意见。SQS的长轮询机制意味着轮询并不是“常量”——你不能像自旋锁一样使用它。在这个问题的背景下,我不太确定“非阻塞API”实际上是什么意思,因为队列的目的是在组件之间创建一个弹性缓冲区。这似乎几乎可以被归类为“基于观点的”。 - Michael - sqlbot
SQS 发送一个 HTTP 请求,所谓的非阻塞 API 是指 Node 应用程序将立即发送响应,确认已接收请求,然后处理信息。 - Ashwani Agarwal
如果您的应用程序发送响应并继续处理请求,如果您不将正在处理的请求存储在某个地方以防止在出现崩溃、错误、过载或其他任何错误时丢失,那么您将面临问题。 - Michael - sqlbot
@AshwaniAgarwal,生产者和消费者是否在您的基础设施内的局域网中运行?如果您想使用SQS并且所有其他组件都在您的数据中心中,您可能需要与您的OPs团队进行核实。 - techuser soma
2个回答

3
SQS使用XML over http,RabbitMQ使用AMQP,所有协议都有开销。序列化/反序列化有成本。Amazon SQS和AMQP都非常高效。我建议从计算中排除这些“开销”,而是专注于您的其他要求。
使用队列的一个重要优点是处理激增活动。如果您获得100K次点击,并需要发送100K条消息,并且尝试将其实现为服务间调用(非阻塞或其他方式),则您将在系统可扩展性方面遇到真正的限制(从端口数等方面)。如果您将100K条消息放在队列中,则可以在远程服务器的“空闲时间”基本上处理这些消息。
此外,如上所述,队列具有更难以自己实现的持久性。如果您的数据不重要,则这不是一个大问题,但如果这些数据很重要,则确实需要某些推送到持久存储(例如SQS或Rabbit持久队列)的东西...

这个答案比我用两倍的字数可能更全面地解决了这些问题。有趣的是,它基本上完全没有记录,但是通过将Accept:Content-Type:头都设置为application/json,SQS也可以完全使用JSON进行所有API交互,这使得在自己的环境中使用SQS变得更加容易(这是我喜欢的)。 - Michael - sqlbot

2
我来晚了,但最近我开始使用非阻塞I/O,并且发现NIO的好处特别明显,尤其是在调用无法访问消息队列的外部服务时。使用固定连接池将确保使用非阻塞I/O处理10万个问题,而不会创建太多连接。
在调用内部服务时,消息队列是首选,但是假设您没有这个选项,您可以利用重试机制和连接池来使用NIO,从而获得与消息队列相同的可扩展性。这是基于接收器能够处理NIO调用的负载情况。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接