可以将REST和消息传递结合用于微服务吗?

时间:2019-06-11 14:55:13

标签: rest microservices messagebroker event-bus cap-theorem

我们拥有基于微服务架构的应用程序的第一个版本。我们使用REST进行内部和外部通信。

现在,我们想从CP(CAP定理)*切换到AP,并使用消息总线在微服务之间进行通信。 关于如何基于Kafka,RabbitMQ等创建事件总线的信息很多。 但是我找不到结合REST和消息传递的最佳实践。 例如,创建汽车服务,然后需要添加不同的汽车组件。为此,将REST与POST请求一起使用会更有意义。另一方面,对于基于事件的方法,预订汽车的服务将是一项不错的任务。

当您具有不同的字典和业务逻辑功能时,您是否有类似的方法?您如何结合它们?只是分别支持两种方法?还是用一种方法统一它们?

*对于第一个版本,我们同意选择一致性和分区容限。但是现在可用性对我们而言变得越来越重要。

1 个答案:

答案 0 :(得分:2)

最下面的底线:您正在寻找Command Query Responsibility Segregation;它定义了一种架构模式,用于分解从查询数据到要求运行流程的职责。简短的答案是,您不想以阻塞的方式在查询或流程中将两者混在一起。该答案的其余部分将详细说明原因以及您可以尝试做的三种不同方式。

这个答案是我对微服务的简短体验。我的真心实意:我从零开始创建了微服务拓扑(几乎是零知识),并且正如他们所说的那样,一直沿用到每个分支。

从零知识开始的好处之一是,我创建的第一个拓扑混合使用了服务内同步和阻塞(HTTP)通信(从包含它的服务中检索操作所需的数据),和消息队列+异步事件以运行操作(用于Commands)。

我将定义两个术语:

命令:告诉服务执行某项操作。例如,“运行ETL批处理作业”。您期望从中得到输出;但这一定是您无法可靠等待的过程。命令有副作用。由于此操作,某些事情会发生变化(如果什么也没有发生并且什么都没有变化,那么您就什么也没做)。

查询:向服务询问其保存的数据。此数据可能是由于发出命令而存在的,但要求数据不应有副作用。由于收到查询,因此无需 即可运行任何Command操作。

无论如何,回到拓扑。

级别1:混合使用HTTP和事件

对于第一个拓扑,我们将同步查询与发出的异步事件混合在一起。这是个问题。

消息总线本质上是可以观察到的。 RabbitMQ中的一项设置或事件源,您可以观察系统中的所有事件。这具有一些良好的副作用,即在过程中发生某些事情时,您通常可以找出导致该状态的事件(如果遵循事件驱动的范例+状态机)。

如果不检查网络流量或记录这些请求,就无法观察到HTTP调用(它本身有问题,因此在正常操作中,我们将从“不可行”开始)。因此,如果您将基于消息的流程和HTTP调用混合在一起,那么您将遇到无法分辨正在发生什么的漏洞。您会发现一些地方,由于网络错误,您的HTTP调用未返回数据,因此您的服务没有继续执行该过程。您还需要为HTTP调用挂接Retry / Circuit Breaker模式,以确保它们至少尝试几次,但是然后您必须区分“由于关闭而没有启动”和“因为暂时很忙而没有启动”之间的区别。 “。

简而言之,将两种方法混合用于命令驱动程序并不是很灵活。

级别2:事件定义了数据的RPC /内部请求/响应;查询是外部的

在此成熟度模型的第二步中,将命令和查询分开。命令应使用事件驱动的系统,查询应通过HTTP进行。如果需要查询命令的结果,则发出一条消息,并在消息总线上使用请求/响应模式。

这也有好处和问题。

从收益的角度来看,即使它跳过了多个服务,您的整个命令现在还是可以观察到的。您还可以通过重新运行事件来重播系统中的进程,这对于跟踪问题很有用。

在问题方面,现在您的某些事件看起来很像查询;现在,您正在重新创建HTTP中用于消息的漂亮的HTTP和REST语义;这并不是十分有趣或有用。例如,一个404告诉您REST中没有数据。对于基于消息的事件,您必须重新创建这些语义(关于我找不到的主题,Youtube上有一个很好的会议演讲,但是一个团队却竭尽全力做到这一点)。

但是,您的事件现在是异步的并且是非阻塞的,并且每个服务都可以重构为将响应给定事件的状态机。需要注意的是,这些事件应包含操作所需的所有数据(导致消息在整个过程中不断增长)。

您的查询仍然可以使用HTTP进行外部通信;但是对于内部命令/进程,您将使用消息总线。

我也不推荐这种方法(尽管这是第一种方法的进步)。我不建议您这样做,因为您的事件开始会发生混乱,在微服务系统中,整个系统中的合同都是相同的。

级别3:数据生产者将数据作为事件发出。消费者记录使用数据。

成熟度模型中的第三步(当我离开项目时,我们就进入了这种范式)是用于生成数据的服务,以便在生成数据时发出事件。然后,这些数据将由侦听这些事件的服务记录下来,这些服务将使用(可能是)过时的数据来执行其操作。外部客户仍然使用HTTP。但是在内部,当生成新数据时,您会发出事件,并且关心该数据的每个服务都将存储该数据以在需要时使用。这是Michael Bryzek的演讲Designing Microservices Architecture the Right way的症结所在。 Michael Bryzek是白标电子商务公司Flow.io的CTO。

如果您想获得更深刻的答案以及其他问题,我将带您到my blog post on the subject