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

Posted

技术标签:

【中文标题】微服务之间的通信——请求数据【英文标题】:Communication between microservices - request data 【发布时间】:2018-10-31 10:06:04 【问题描述】:

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

例如(虚构的例子,只是为了说明):

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

现在,如果我想从客户端应用添加新订单,我需要知道用户地址。所以请求会是这样的:

客户端 -> 微服务 B (createOrder for userId 5) -> 微服务 A (getUser with id 5)

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

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

选项:

使用 RestAPI, 使用 AMQP,如 RabbitMQ 并通过 RPC 处理此问题。 (https://www.rabbitmq.com/tutorials/tutorial-six-dotnet.html)

我不知道什么对性能更好。通过 RabbitMQ 或 RestAPI 调用更快吗? 微服务架构的最佳解决方案是什么

【问题讨论】:

这取决于此应用程序的要求。很难从虚构的例子中回答。对我来说,听起来添加订单可能是异步的。也可能是服务 B 已经知道系统中的用户——比如读取事件,然后它只是内存中的查找。 在我看来,将用户存储在一些内存中可能会消耗内存。存储其他微服务数据不是反模式吗?既然如此,您认为最好的选择是 HTTP 吗? 是的,在这种情况下。 HTTP。 如果你想用 API 来做,我强烈建议你使用 gRPC 而不是 http。它非常快。但 AMQP 也非常快,因为它具有始终连接的特性。 【参考方案1】:

在您的情况下,使用直接 REST 调用应该没问题。

选项 1 使用 Rest API:

当您需要同步通信时。比如你的情况。这个选项很合适。

选项 2 使用 AMQP:

当您需要异步通信时。例如,当您的订单服务创建订单时,您可能希望通知产品服务以减少产品数量。或者您可能希望通知用户服务已成功下订单。

我强烈推荐看看http://microservices.io/patterns/index.html

【讨论】:

【参考方案2】:

在 REST API 和基于事件的设计或两者之间进行选择完全取决于您的服务的通信行为

您所做的是根据您的要求选择REST API,您可以在其中看到服务之间的同步行为 并使用 基于事件的设计,您会发现服务需要 异步行为,两者结合也没有什么坏处。

理想情况下,对于进程间通信协议,最好使用消息传递,而对于客户端服务,REST API 最适合。 查看microservices.io中的沟通方式

基于 REST 的架构

优势

    当您需要同步环境时,请求/响应非常简单且最适合。

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

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

缺点

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

    服务之间的一对一映射。

    Rest 使用 HTTP,它是建立在 TCP/IP 之上的通用协议,在使用它来传递消息时会增加大量开销。

事件驱动架构

优势

    事件驱动的架构对 API 开发人员很有吸引力,因为它们在异步环境中运行良好。

    松散耦合,因为它将服务解耦,因为在一次服务的事件中,多个服务可以根据应用程序要求采取行动。将任何新的消费者插入生产者都很容易。

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

缺点

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

【讨论】:

【参考方案3】:

就我个人而言,我不喜欢为 RPC 使用消息代理。它增加了不必要的复杂性和开销。

如何在用户 Web 服务中托管长期存在的 RabbitMQ 消费者?如果你让它成为一些静态单例,在你的 web 服务中你如何处理扩展和并发?或者你让它成为一个独立的守护进程?现在您有两个用户应用程序而不是一个。如果您的用户消费者速度变慢,当它使用请求消息时,订单服务上下文可能已超时并发送另一条消息或放弃,会发生什么情况。

对于 RPC,我建议使用简单的 HTTP。

有一种涉及消息代理的模式可以避免同步网络调用的需要。该模式是让服务使用来自其他服务的事件并将该数据本地存储在自己的数据库中。然后,当 Orders 服务需要用户记录时,它可以从自己的数据库中访问它。

在您的情况下,您的“用户”应用不需要了解有关订单的任何信息,但您的“订单”应用需要了解有关用户的一些详细信息。因此,每次添加、修改、删除用户等时,用户服务都会发出一个事件(UserCreated、UserModified、UserRemoved)。 Orders 服务可以订阅这些事件并仅存储它需要的数据,例如用户地址。

好处是,在请求时,您的 Orders 服务对另一个服务的同步依赖减少了。测试服务更容易,因为您的请求时间依赖性更少。然而,也有一些缺点,例如用户记录更改发生与 Orders 应用程序接收之间存在一些延迟。需要考虑的事情。

更新 如果您确实使用 RabbitMQ for RPC,请记住使用消息 TTL 功能。如果客户端将超时,则将消息过期设置为该时间段。这将有助于避免消费者浪费工作,并避免队列在负载下备份。消息代理上的 RPC 的一个问题是,一旦队列填满,它可能会增加较长的延迟,需要一段时间才能恢复。将消息过期设置为客户端超时有助于避免这种情况。

关于用于 RPC 的 RabbitMQ。通常我们使用消息代理来解耦和持久化。看 RPC 是一种同步通信,也就是我们在等待响应,那么持久性就不是考虑因素了。这让我们脱钩了。问题是,与通过网关或 Docker 服务名称对 HTTP 进行的解耦相比,这种解耦是否能为您带来任何好处?

【讨论】:

感谢您的提交。 RabbitMQ 是 Docker 中的独立微服务。但你是对的,对于超时和这些事情,HTTP 可能值得使用。我喜欢捕获事件的想法,但存在问题,微服务订单可能会关闭,而且他的数据库中没有该用户。而且它在微服务方面是相当反模式的,它只做一件事。 好吧,RabbitMQ 是一个持久的消息系统。这是使用它的要点之一。如果一项服务关闭,那么没有问题,您可以在服务恢复时使用该事件。面对瞬息万变的消费者,我们可以获得可靠的消息传递。 此外,这种“反模式”在微服务中也是相当常见的模式。我不确定你从哪里得到这个想法。我想说一个更大的反模式是与多个其他服务直接耦合,你正在走向分布式单体。还要考虑当用户服务不可用时会发生什么,确保您可以使用重试和断路器,但如果它关闭几分钟,这将无济于事。当数据已经在您的服务本地时,您将获得更好的可靠性和更低的延迟。它有取舍,但我认为你不能称之为反模式。 好吧,这听起来很合理。我正在与微服务上的复制数据库作斗争。我不知道这是否是最好的主意。如果您认为必须做的是,来自用户的模型必须在订单中,并且还必须进行事件处理。如果有更多像订单这样的服务需要用户提供一些数据,那么这可能是一场噩梦。不包括可能将数据作为用户的其他服务。并且不计算用户数据上下文可能会随着时间的推移而改变。 我要说的最后一件事是。忘记所有其他权衡,如果速度是您的第一要务,那么我建议您运行基准测试以查看在您的情况下哪个更快。确保为 RabbitMQ 使用非持久消息。我在以前的项目中使用过 ZeroMQ,其性能非常出色,但代价是一些额外的复杂性。如果您的技术堆栈支持,也请查看 GRPC。

以上是关于微服务之间的通信——请求数据的主要内容,如果未能解决你的问题,请参考以下文章

REST 微服务之间的通信:延迟

如何授权微服务内部通信?

通过 Docker 主机名在两个微服务之间进行通信

相互通信的微服务 - 如何?

微服务架构模式: 大魏再学微服务系列1

微服务架构如何运作?