在我之后重复:
REST和异步事件不是替代方案。它们是完全正交的。
您可以拥有一个或另一个,或同时拥有两个或两者都不存在。对于完全不同的问题领域,它们是完全不同的工具。实际上,通用的请求-响应通信绝对能够异步,事件驱动和容错。
作为一个简单的示例,AMQP协议通过TCP连接发送消息。在TCP中,每个数据包都必须由接收方确认。如果数据包的发送方未收到该数据包的ACK,它将继续重新发送该数据包,直到被ACK确认或直到应用程序层“放弃”并放弃连接为止。显然,这是一个非容错的请求-响应模型,因为每个“数据包发送请求”都必须具有一个伴随的“数据包确认响应”,并且由于无法响应而导致整个连接失败。然而,AMQP是用于异步容错消息传递的标准化且被广泛采用的协议,它通过TCP进行通信!是什么赋予了?
这里发挥作用的核心概念是,可伸缩的松耦合容错消息传递是由您发送的消息而不是如何发送的消息定义的。换句话说,在应用层定义了松散耦合。
让我们看一下直接与RESTful HTTP或与AMQP消息代理间接通信的两个方面。假设甲方希望将JPEG图像上传到乙方,乙方将对图像进行锐化,压缩或增强。甲方不需要立即处理该图像,但需要对其进行引用以供将来使用和检索。这是REST中可能采用的一种方法:
- 甲方通过以下方式向乙方发送HTTP
POST
请求消息:Content-Type: image/jpeg
- 乙方在等待时处理图像(如果图像较大,则处理很长时间),可能会做其他事情
- 乙方将HTTP
201 Created
响应消息发送到甲方,该消息的Content-Location: <url>
头带有链接到已处理图像的标头
- 甲方认为其工作已经完成,因为它现在已经参考了已处理的图像
- 将来某个时候,当甲方需要经过处理的图像时,它会使用先前
Content-Location
标头中的链接来获取它
该201 Created
响应码告诉客户,不仅是他们的请求成功,这也创造了新的资源。在201响应中,Content-Location
标头是指向创建的资源的链接。这是在RFC 7231第6.3.2和3.1.4.2节中指定的。
现在,让我们看看这种交互如何在AMQP之上的假设RPC协议上进行:
- 甲方向AMQP消息代理(称为Messenger)发送一条包含该图像的消息以及将其路由到乙方进行处理的说明,然后使用该图像的某种地址响应甲方
- 甲方等待,可能正在做其他事情
- Messenger将甲方的原始消息发送给乙方
- 乙方处理消息
- 乙方向Messenger发送一条消息,其中包含处理后图像的地址和将消息路由至甲方的说明
- Messenger向乙方发送来自乙方的消息,其中包含已处理的图像地址
- 甲方认为其工作已经完成,因为它现在已经参考了已处理的图像
- 将来某个时候,当甲方需要图片时,它会使用该地址(可能是通过向其他方发送消息)来检索图片
您在这里看到问题了吗?在这两种情况下,只有在乙方处理完图片后,甲方才能获得图片地址。然而,甲方并不需要立即使用该图像,并且,即使处理完成,也可以毫不关心!
我们可以通过使乙方告诉A中的B AMQP的情况下很容易地解决这个接受的图像进行处理,给人的地址,其中图像将完成处理后。然后,乙方可以在将来某个时候向A发送一条消息,指示图像处理已完成。AMQP消息救援!
除了猜测什么:您可以使用REST实现相同的目标。在AMQP示例中,我们将“这里是已处理的图像”消息更改为“正在处理图像,稍后可以获取”消息。要在RESTful HTTP中做到这一点,我们将再次使用202 Accepted
代码Content-Location
:
- 甲方通过以下方式向甲方发送HTTP
POST
消息:Content-Type: image/jpeg
- 乙方立即发回一个
202 Accepted
包含某种“异步操作”内容的响应,该内容描述了处理是否完成以及在处理完成后该图像在哪里可用。还包括一个Content-Location: <link>
标头,该标头在202 Accepted
响应中是指向由响应主体表示的资源的链接。在这种情况下,这意味着它是我们异步操作的链接!
- 甲方认为其工作已经完成,因为它现在已经参考了已处理的图像
- 将来某个时候,甲方需要处理的图像时,它首先获取链接到标头中的异步操作资源,
Content-Location
以确定处理是否完成。如果是这样,则甲方然后使用异步操作本身中的链接来获取已处理的图像。
唯一的区别是在AMQP模型中,乙方告诉甲方何时完成了图像处理。但是在REST模型中,甲方检查在实际需要图像之前是否进行了处理。这些方法具有同等的可伸缩性。随着系统的变大,异步AMQP和异步REST策略中发送的消息数量都以等效的渐近复杂性增加。唯一的区别是客户端发送的是额外的消息,而不是服务器。
但是REST方法还有很多技巧:动态发现和协议协商。考虑同步和异步REST交互是如何开始的。甲方向乙方发送了完全相同的请求,唯一的不同是乙方响应的特定成功消息。如果甲方希望选择图像处理是同步还是异步该怎么办?如果甲方不知道乙方是否能够进行异步处理怎么办?
嗯,HTTP实际上已经为此提供了一个标准化协议!它称为HTTP首选项,特别respond-async
是RFC 7240第4.1节的首选项。如果甲方需要异步响应,则它包含Prefer: respond-async
带有其初始POST请求的标头。如果乙方决定接受该请求,它将发回包含的202 Accepted
响应Preference-Applied: respond-async
。否则,乙方将简单地忽略Prefer
标头并201 Created
像往常一样发送回去。
这使甲方可以与服务器进行协商,以动态地适应与之通信的任何图像处理实现。此外,使用显式链接意味着甲方除乙方外无需了解其他任何方:没有AMQP消息代理,没有神秘的甲方知道如何将图像地址实际转换为图像数据,没有第二个B异步如果需要同时发出同步请求和异步请求,等等。它仅描述所需的内容,可选的内容,然后对状态码,响应内容和链接做出反应。加入Cache-Control
标头提供有关何时保留本地数据副本的明确指示,现在服务器可以与客户端协商客户端可以保留其本地(甚至离线!)资源的资源。这就是您在REST中构建松耦合的容错微服务的方式。