【问题标题】:Coupling in microservices architecture微服务架构中的耦合
【发布时间】:2018-12-09 20:46:53
【问题描述】:

在处理微服务架构中的应用程序时,我偶然发现了有关服务之间耦合的问题。

这是订购产品的典型应用。将服务作为产品目录运行似乎是合理的。我们的 JavaScript 客户端可以向该服务询问可用的产品并在浏览器中显示它们。当用户点击产品时,我们必须创建订单。我们想在另一个服务中管理订单。因此创建了一个订单 - 这意味着用户 X 订购了产品 Y。在技术层面上,我们只是将用户 ID 和产品 ID 保存在数据库中。

总结一下:

产品服务

产品类别:
产品 ID、产品名称

订单服务

订单类别:
订单 ID、产品 ID、用户 ID、订单日期

现在让我们想象以下场景 - 在 JavaScript 客户端中,我们想列出用户订购的所有产品。 Orders 服务提供给定用户的产品 ID 列表。但是用户关心的是产品名称,而不是 id。不幸的是,Orders 服务对产品名称一无所知。

我们可以通过以下几种方式解决这个问题:

  • 简单地假设客户负责获取它需要的信息。因此,在调用 Orders 服务并获取产品 ID 列表后,它会再次调用 Products 服务,传递产品 ID 并获取相应的产品名称作为响应。然后客户端将两个响应组合成有用的东西。这种方法使我们的服务保持清洁,而不会将领域知识从一个服务泄漏到另一个服务。但这需要在客户端做更多的工作。

  • Orders 服务在请求订购产品时会在后端调用 Products 服务。它检索产品名称,组装包含 orderDate 和 productName 的响应并将其发送给客户端。客户要做的就是呈现数据。这种方法的缺点是,Orders 服务现在获得的关于产品的知识比必要的要多。

  • 订单服务中的产品名称信息重复。创建订单时,我们不仅传递产品 ID,还传递产品名称。这意味着 Order 类将如下所示: 订单类别:
    订单 ID、产品 ID、产品名称、用户 ID、订单日期
    现在我们可以轻松地提供有关订单的完整信息,而无需额外调用产品服务。这一次订单服务对产品的了解也太多了。好处在于,即使 Products 服务宕机,Orders 服务也能提供相关数据。

是否可以将这些方法中的任何一种视为最佳实践?还是有不同的解决方案?

【问题讨论】:

  • 复制信息。这不是真正的重复。如果您将来更改产品名称,用户应该看到什么?因为它可能是按顺序排列的,所以它并不是真正的重复。
  • 我同意,只复制所需的数据似乎是明智的选择。如果需要,您还可以考虑使用消息队列将产品名称或价格更改推送到购物篮预购中。订单完成后,产品信息可能不应更改。
  • 同意。在订单完成之前,价格可能会发生变化。这就是亚马逊的运作方式。篮子里的东西等不断变化的价格。订单完成后,必须及时捕获。不能在不告知客户的情况下更改约定价格。

标签: microservices coupling


【解决方案1】:

在 eShopOnContainers 示例 (https://github.com/dotnet-architecture/eShopOnContainers) 中,他们在创建订单商品时添加以下字段:

        public void AddOrderItem(int productId, string productName, decimal unitPrice, decimal discount, string pictureUrl, int units = 1)

这会复制目录信息,但是因为这是记录的时间点快照。这比链接到原始数据要安全得多。

在用户旅程的这一点上,您处于订单域中,如果用户正在查看订单,您可以提供目录链接。但是,订单服务应该能够独立运行。链接回目录以获取产品信息会阻止 Order 服务拥有自己的数据。

一个噩梦般的场景是目录中的价格发生变化......历史订单会发生什么?

【讨论】:

    猜你喜欢
    • 2019-11-01
    • 2017-10-06
    • 2023-03-31
    • 1970-01-01
    • 2017-10-12
    • 2015-12-26
    • 2021-11-02
    • 2020-09-13
    相关资源
    最近更新 更多