首页 > 解决方案 > 使用 RabbitMq 的微服务之间的数据一致性

问题描述

我正在尝试为我公司处理订单管理的一些简单内部系统设置一个实用的微服务演示,但是我很难理解大规模微服务之间的数据一致性。

我已经为微服务确定了一个简单的场景——我们正在运行的一个当前应用程序在我们的网站上处理订单并更新客户的“账户信用”——基本上是他们可以在他们的账户需要之前花在我们身上的未付款项审查。

我试图将这个非常简单的需求分解为几个微服务。这些定义如下:

简单的微服务结构,展示客户微服务和订单微服务

API 提供了各种不同级别的功能 - 它允许我们创建一个新客户,这会触发以下内容:

新客户服务流程

使用SQL,我们可以在数据库内工作时做一些乐观的查询,通过伸缩微服务(EG:Order Microservice的两个实例,每个微服务,但不是每个实例微服务有自己的数据库)。

例如,我们可以执行以下操作并假设 SQL 将管理锁定,这意味着当同时处理两个订单时,数字应该以正确的数字结束:

UPDATE [orderms].[customers] SET CreditLimit = CreditLimit - 100, NoOfOrders = NoOfOrders + 1 WHERE CustomerId = 1

综上所述,如果信用是 1000 并且处理了 2 个 100 的订单,并且每个订单被分配到“订单”微服务的不同实例,我们应该能够假设正确的数字将出现在客户表中Order 微服务(基于 MSSQL 查询的锁定应该自动处理这个问题)。

当我们尝试将这些集成回客户微服务时,问题就来了。我们将有两条消息,来自订单微服务的每个实例,作为事件传递,示例如下:

通过微服务处理新订单

鉴于上述情况 - 我们很可能会按照以下方式更新“客户”SQL 表(这是两个查询):

UPDATE [customerms].[customers] SET CreditLimit = 900.00 WHERE CustomerId = 1
UPDATE [customerms].[customers] SET CreditLimit = 800.00 WHERE CustomerId = 1

但是 - 根据这些“客户”微服务的运行速度,实例 #1 目前可能正在创建几个新客户,因此处理此请求的速度可能比实例 #2 慢,这意味着将执行 SQL 查询乱序,因此我们将留下 CreditLimit 为 800(正确)的“Order”数据库和 CreditLimit 为 900(不正确)的 Customer 微服务。

在单体应用程序中,如果确实需要,我们通常会添加一个锁定元素(或可能是互斥锁),否则将根据订单微服务中的功能依赖 SQL 锁定,但是由于这是一个分布式进程,这些都不是旧方法将适用。

有什么建议吗?我似乎无法以某种方式看到过去?

标签: rabbitmqmicroservices

解决方案


我认为的解决方案

在两个微服务中保持初始信用额度。假设初始信用额度为 1000,并将其设置在两个微服务数据库中。处理订单时,首先在订单微服务处减少它,而不是发送信用额度(800、900 或任何金额),而是发送必须从客户微服务信用额度中减少的金额。

假设您处理了两个订单,每个订单价值 100。首先降低订单微服务的信用额度,然后生成两个事件,每个事件 100 美元将由客户服务消费并在此结束。这样,无论它们到达的顺序如何,您只需减少该数量即可。

事件溯源(更好的方法)

带有乐观锁定的事件溯源是您可以采用的方法。在这种模式下,您无需保存实体的特定状态,而是将所有事件保存在数据库中。这是一个仅附加的存储,事件按照它们到达的顺序存储。在这种情况下,您需要重播事件以达到特定状态的信用额度。在这种情况下,您将拥有所有历史记录。请记住,如果出现任何不一致的情况,您没有任何日志可以回退,但有了事件溯源,您就有了。


推荐阅读