微服务之间的通信 - 请求数据

14

我正在处理微服务之间的通信。

例如(虚构的例子,仅供说明):

  • 微服务A - 存储用户(getUser等)
  • 微服务B - 存储订单(createOrder等)

现在,如果我想要从客户端应用添加新订单,我需要知道用户地址。因此,请求将如下所示:

客户端 -> 微服务B(为用户ID 5创建订单)-> 微服务A(使用ID 5获取用户)

微服务B将使用来自用户微服务的详细信息(地址)创建订单。

需要解决的问题:如何有效地处理微服务A和微服务B之间的通信,因为我们必须等待响应返回?

选项:

我不知道哪种方案对性能更好。通过RabbitMQ进行调用是否更快,还是使用RestAPI? 什么是微服务架构的最佳解决方案


这取决于此应用程序的要求。很难从虚构的例子中回答。对我来说,听起来像是添加订单可以是异步的。也可能是服务B已经知道系统中的用户-例如从读取事件,那么它只是一个内存查找。 - Jocke
1
在我看来,将用户存储在某些内存中可能会消耗大量内存。而且,将其他微服务的数据存储起来不是反模式吗?你认为,在这种情况下,最好的选择是HTTP吗? - David Pavelka
是的,在这种情况下。HTTP。 - Jocke
1
如果你想使用API来完成它,我强烈建议你使用gRPC而不是http。它非常快。 但是AMQP也非常快,因为它始终保持连接状态。 - Amin Shojaei
3个回答

9
在您的情况下,直接使用REST调用应该是可以的。
选项1 使用Rest API:
当您需要同步通信时。例如,您的情况。此选项适合。
选项2 使用AMQP:
当您需要异步通信时。例如,当您的订单服务创建订单时,您可能希望通知产品服务以减少产品数量。或者您可能希望通知用户服务,用户的订单已成功下达。
我强烈建议查看http://microservices.io/patterns/index.html

5

一切都取决于您的服务通信行为,选择REST API、事件驱动设计或两者兼备

根据您的需求,如果您发现服务之间存在同步行为,则可以选择REST API;如果您发现服务需要异步行为,则可以选择事件驱动设计;当然,两者兼备也没有问题。

理想情况下,对于进程间通信协议,最好选择消息传递方式,而客户端服务方面,则最适合使用REST API。请参考microservices.io中的通信风格。

基于REST的架构

  • 优点

    1. 请求/响应模式易于使用,最适合同步环境。

    2. 系统更简单,因为没有中间代理。

    3. 促进编排,即服务可以根据其他服务的响应采取行动。

  • 缺点

    1. 服务需要发现服务实例的位置。

    2. 服务之间是一对一映射。

    3. REST使用HTTP,这是建立在TCP/IP之上的通用协议,当使用它传递消息时会添加大量开销。

事件驱动架构

  • 优点

    1. 事件驱动架构对于API开发人员非常有吸引力,因为它们在异步环境中运行非常好。

    2. 松散耦合,因为它将服务解耦,一次服务事件可以基于应用程序要求触发多个服务的操作。很容易将任何新的消费者插入到生产者中。

    3. 提高可用性,因为消息代理会缓冲消息直到消费者能够处理它们。

  • 缺点

    1. 消息代理的额外复杂性,必须具备高可用性
    2. 调试事件请求并不容易。

3
个人而言,我不喜欢使用消息代理进行RPC。它增加了不必要的复杂性和开销。
那么,您如何在您的用户Web服务中托管长时间运行的RabbitMQ消费者?如果将其设置为静态单例,则您的Web服务如何处理扩展性和并发性?还是将其设置为独立的守护进程?现在您有两个用户应用程序而不是一个。如果您的用户消费者速度变慢,当它消费请求消息时,订单服务上下文可能已经超时并发送了另一条消息或放弃了。
对于RPC,我建议使用简单的HTTP。
有一种涉及消息代理的模式可以避免同步网络调用的需要。该模式是服务从其他服务消耗事件并在其自己的数据库中存储该数据。然后,当Orders服务需要用户记录时,它可以从自己的数据库中访问它。
在您的情况下,您的用户应用程序不需要知道任何关于订单的信息,但是您的订单应用程序需要知道有关用户的某些详细信息。因此,每次添加、修改、删除用户等操作时,用户服务都会发出事件(UserCreated,UserModified,UserRemoved)。订单服务可以订阅这些事件并仅存储它所需的数据,例如用户地址。
好处是,在请求时,您的订单服务对另一个服务的同步依赖性减少了一个。测试服务更容易,因为您有较少的请求时间依赖性。但是也有一些缺点,例如在用户记录更改发生并被订单应用程序接收之间可能存在一些延迟。需要考虑的事情。
更新: 如果您决定使用RabbitMQ进行RPC,则请记住利用消息TTL功能。如果客户端超时,则将消息到期设置为该时间段。这将有助于避免消费者的浪费工作,并避免在负载下排队被堵塞。 RPC通过消息代理的一个问题是,一旦队列填满,它可能会增加长时间的延迟,而且恢复时间也要花费一定的时间。将消息到期设置为客户端超时有助于避免这种情况。
关于RabbitMQ用于RPC。通常,我们使用消息代理来解耦和提高可靠性。由于RPC是同步通信,即我们正在等待响应,因此可靠性不是重点。这使我们只需考虑解耦。问题是,相对于通过网关或Docker服务名称进行解耦,使用消息代理是否实现了更好的解耦?

感谢您的提交。RabbitMQ是在Docker中作为独立的微服务运行的。但是您说得对,对于超时等问题,使用HTTP可能更值得考虑。我喜欢捕获事件的想法,但有一个问题,微服务订单可能会关闭,那么他的数据库中就没有该用户信息了。此外,从微服务的角度来看,这也是一种反模式,因为它旨在只做一件事情。 - David Pavelka
RabbitMQ 是一个可靠的消息系统。 这就是使用它的优点之一。 如果一个服务停止工作,那么没问题,当服务重新启动时您可以消费事件。 在瞬态消费者面前,我们获得可靠的消息传递。 - Vanlightly
如果服务崩溃了,就会有负载均衡器识别并将通信重定向到其他实例。因此,希望同步调用一切正常。对于这些调用,使用HTTP更好吗? - David Pavelka
是的,它会将所有内容都作为HTTP返回给我。如果我想要调用同步的东西,我可以通过RPC(由RabbitMQ支持)来实现。对我来说重要的是速度。我不知道哪个会更快地响应(HTTP还是RPC)。所以你会更喜欢RPC吗?我需要在这两者之间做出决定。 - David Pavelka
1
最后我要说的是,如果速度是你的首要考虑因素,那么忘记其他所有权衡,我建议你运行基准测试来查看在你的情况下哪个更快。确保你使用RabbitMQ的非持久化消息。我之前在一个项目中使用过ZeroMQ,性能非常出色,但代价是一些额外的复杂性。此外,如果你的技术栈支持,也可以看看GRPC。 - Vanlightly
显示剩余3条评论

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