如何在微服务中跨服务执行验证
Posted
技术标签:
【中文标题】如何在微服务中跨服务执行验证【英文标题】:How to perform validation across services in microservices 【发布时间】:2018-07-28 00:45:23 【问题描述】:假设有两个微服务:订单和库存。有一个 API in order 服务接受 ProductId
、Qty
等并下订单。
理想情况下,仅当库存服务中存在库存时才允许下订单。人们建议使用 Saga 模式或任何其他分布式事务。这很好,最终会利用一致性。
但是如果有人想滥用系统怎么办。他可以推送无效或缺货的产品 (ProductId
s) 的订单。系统将接收所有这些订单并将这些订单放入队列中,库存服务将处理这些无效订单。
难道不应该提前处理(在订单服务中)而不是将这些无效订单推到下一个级别(特别是在 productId 无效的情况下)
处理这些情况的建议是什么?
【问题讨论】:
是否存在Orders
必须继续工作的业务要求,即使Inventory
已关闭,如果是,在减少或延迟服务方面可接受的权衡是什么?
【参考方案1】:
处理这些情况有哪些建议?
让您的订单服务访问它需要过滤掉不受欢迎的订单的数据。
基本情节是,虽然库存服务是库存状态的权威,但您的订单服务可以使用库存的缓存副本确定接受哪些订单。
对库存的更改最终会复制到订单服务的缓存中——这就是您的“最终一致性”。如果 Inventory 暂时下线,Order 可以继续根据其缓存中的信息提供业务价值。
您可能还需要注意缓存中数据的年龄 - 如果自上次更新缓存以来已经过去了太多时间,那么您可能需要更改策略。
您的“聚合”通常不会知道它们正在处理缓存;您将与订单数据一起传递一个域服务,该服务支持聚合完成其工作所需的查询;域服务的实现访问缓存以提供答案。
只要不让滥用者提供自己的域服务实例,或者直接操作缓存,就可以保证缓存数据的完整性。
(例如:当您测试聚合时,您可能会提供针对您的特定测试场景调整的缓存数据;这种劫持不是您希望滥用者能够做到的事情在您的生产环境中实现)。
【讨论】:
感谢@VoiceOfUnreason 的回复!为您的回答 +1,您的建议与我的想法一致。【参考方案2】:您绝对希望预先确保可以捕获尽可能多的无效业务案例。有几种方法可以解决这个问题。这与在航空公司预订座位时的情况相同。虽然他们会超额预订,但我们暂时忽略 :)
选项 1:您可以保留库存商品作为订单的一部分。这更像是一种悲观的方法,但您的物品会在您等待确认时被保留。
选项 2:只有在有库存商品但没有保留并希望以后有货的情况下,您才可以接受订单。
如果库存商品不可用并且您希望支持延期交货,您也可以创建延期交货。
如果您选择选项 1,如果某件商品已为客户 A 预订,而客户 B 出现但无法订购,则您可能会错过客户。如果客户 A 决定不完成订单,则库存商品将再次可用,但客户 B 现在已前往其他地方尝试采购该商品。
作为订单履行的一部分,您必须告知库存有界上下文您现在正在取货。但是,您现在可能会发现客户 A 和 B 都接受了他们的报价并为最后一个项目创建了订单。一个人会输。此时,无法履行的将向客户发送一封邮件,并告知他们不幸的情况,并可能创建延期交货;或要求客户在 X 天后重试。
您的领域专家应该决定如何处理这些场景,这完全取决于项目的受欢迎程度等。
【讨论】:
这很好地回答了“缺货”的问题,但在这种情况下,最终的一致性几乎让人觉得很容易。我相信这个问题主要是关于不存在的产品的错误订单。 @guillaume31:这是需要预先检查产品是否存在的地方。我想收到包含不存在的产品的RegisterOrderRequest
会很奇怪,但是如果有人不信任来源,则需要检查它们在哪里接收到系统 --- 通常你不会进入,比如说, 一个 web-api :) 我相信你会同意一个人控制的任何 UI 只会显示有效的产品,但从其他任何地方收到的任何东西都可能不会;即便如此,安全的方法是在发送“RegisterOrderComand”之前验证该请求。
但是你会推荐什么技术解决方案来预先检查这个?微服务之间的直接通信?在 Order
中存储产品 ID 的副本?
感谢@EbenRoux 的回复!正如@guillaume31 指出的那样,问题是如何在技术上做到这一点。
关于信任边界,这些是链接到 UI 的公共 webAPI。但最终用户可以随时使用 Postman 或任何其他工具给他们打电话。【参考方案3】:
我不会试图说服您在下订单之前不要进行此检查,而是像通常那样依赖 Sagas;我会认为这是您必须实现的业务需求。
对我来说,这似乎是一个新的子域:不良行为预防(或者你想怎么称呼它)带有新的责任:防止滥用者。您可以将此责任添加到 Order 微服务,但您会破坏 SRP。所以,应该在另一个微服务中完成。
从您的 API 网关(如果有的话)或 Orders 微服务调用这个新的微服务。
如果您不添加新的微服务(出于不同的原因),那么您可以将这个新功能实现为 Orders 微服务内部的一个模块,但我强烈建议使其与其主机高度解耦(单独和私有的持久性/数据库/表)。
【讨论】:
感谢@Constantin 的回复!这不是业务需求,而是一种安全问题,应尽快检查 Validation 并处理无效请求。您不想接受无效请求并将其提升到一个新的水平。 @Pragmatic 你应该小心你赋予 Orders 微服务什么责任以及如何。我的答案是正确的。以上是关于如何在微服务中跨服务执行验证的主要内容,如果未能解决你的问题,请参考以下文章