从两个不同微服务请求关联数据的最优实现方式是什么?
结论先行
你提到的让cartservice请求catalogservice后返回数据给checkoutservice的方案不推荐,最优方案是按照你参考的微服务最佳实践,采用最终一致性机制同步商品核心数据到上游服务。
方案1(生产级最优,符合最佳实践)
通过集成事件同步商品核心字段到上游服务,有两种落地方式,按需选择即可:
- 同步到
cartservice的Redis存储
当catalogservice中商品发生新增、名称修改、价格调整等操作时,发布ProductChangedEvent事件到RabbitMQ,cartservice订阅该事件,更新本地Redis中对应商品的冗余字段。调整后购物车存储格式如下:
cartId: { { productId: 10, productQuantity : 1, productName: "CCC", productPrice : 10.50 }, { productId: 20, productQuantity : 2, productName: "AAA", productPrice : 20.50 } }
该方式下,checkoutservice仅需调用一次cartservice即可获取所有结账所需的商品全量信息,无需再和catalogservice产生交互,拿到数据后直接通过RabbitMQ fanout模式广播给下游payment、shipping、email服务即可,整个下单链路只存在一次同步调用,耗时最低,耦合最小。
2. 同步到checkoutservice的本地存储
逻辑和上面一致,仅需将订阅ProductChangedEvent的主体换成checkoutservice,同步的商品核心字段存在checkoutservice的本地缓存或数据库中。checkoutservice从cartservice拿到商品ID列表后,直接查询本地存储就能拿到所有商品信息,同样不需要调用catalogservice。
两种方式都完全符合微服务设计原则,避免了长同步调用链,商品数据的秒级最终一致性对于电商购物场景完全可接受,如果担心价格不一致问题,只需要在支付环节加个简单的快照校验即可。
方案2(轻量适配,适合学习项目快速落地)
如果觉得事件同步对于学习项目来说过重,可以调整原有同步调用逻辑:将checkoutservice循环调用catalogservice查询单个商品的逻辑,改为一次性批量传入所有购物车商品ID查询全量信息,仅多一次远程调用,对整体响应时长的影响极小,低并发场景下完全够用。
不推荐方案说明
你提到的由cartservice调用catalogservice返回全量信息的方案,本质只是把同步调用的主体从checkoutservice转移到了cartservice,总耗时没有减少,还额外增加了cartservice和catalogservice的耦合,破坏了cartservice的单一职责,会导致catalogservice故障时cartservice也无法正常提供服务,降低了整体可用性。
架构图问号位置实现说明
标注问号的通信位置,最优实现就是走异步集成事件:由catalogservice发布商品变更事件,上游服务(cartservice或checkoutservice)订阅消费事件完成数据同步,完全避免同步调用依赖。
内容的提问来源于stack exchange,提问作者Baris Ertas
相关产品推荐
相关产品推荐

