在 .NET Core 8 电子商务应用程序中实现 Saga 模式

作者:微信公众号:【架构师老卢】
9-17 18:0
77

在使用 .NET Core 8 构建并部署在 Azure 上的大型电子商务平台上工作,我在保持微服务架构中的数据一致性方面面临许多挑战。事实证明,在管理复杂的分布式事务方面,一种模式是 Saga 模式。在本文中,我将分享我们实现此模式的经验以及我们在此过程中学到的经验教训。

问题:电子商务中的分布式事务 我们的电子商务平台由多个微服务组成,包括:

  1. 订购服务
  2. 2. 库存服务
  3. 3. 支付服务
  4. 4. 运输服务
  5. 5. 通知服务

典型的订单流涉及多个步骤:

1. 创建订单 (Order Service)

2. 预留库存 (Inventory Service)

3. 处理付款(支付服务)

4. 发起发货 (Shipping Service)

5. 发送订单确认(通知服务)

这些步骤中的每一个都涉及更新 service-specific 数据库中的数据。确保这些分布式事务的一致性是一项重大挑战,尤其是在处理流程中任何步骤的故障时。

进入 Saga 模式

Saga 模式为我们提供了一个健壮的解决方案来管理这些分布式事务。我们选择了编排方法,实施了一个中央 OrderSaga 编排器来协调整个订单流程。

以下是 OrderSaga 实现的简化版本:

public class OrderSaga : IOrderSaga
{
    private readonly IOrderService _orderService;
    private readonly IInventoryService _inventoryService;
    private readonly IPaymentService _paymentService;
    private readonly IShippingService _shippingService;
    private readonly INotificationService _notificationService;

    public OrderSaga(IOrderService orderService, IInventoryService inventoryService, 
                     IPaymentService paymentService, IShippingService shippingService, 
                     INotificationService notificationService)
    {
        _orderService = orderService;
        _inventoryService = inventoryService;
        _paymentService = paymentService;
        _shippingService = shippingService;
        _notificationService = notificationService;
    }

    public async Task<OrderResult> ProcessOrder(OrderRequest request)
    {
        var order = await _orderService.CreateOrder(request);

        try
        {
            await _inventoryService.ReserveInventory(order);
            await _paymentService.ProcessPayment(order);
            await _shippingService.InitiateShipping(order);
            await _notificationService.SendOrderConfirmation(order);

            return new OrderResult { Success = true, OrderId = order.Id };
        }
        catch (Exception ex)
        {
            await CompensateOrder(order, ex);
            return new OrderResult { Success = false, Error = ex.Message };
        }
    }

    private async Task CompensateOrder(Order order, Exception ex)
    {
        // Implement compensating transactions
        await _inventoryService.ReleaseInventory(order);
        await _paymentService.RefundPayment(order);
        await _shippingService.CancelShipping(order);
        await _orderService.CancelOrder(order);
        await _notificationService.SendOrderCancellation(order, ex.Message);
    }
}

关键学习和最佳实践

  1. 幂等性至关重要:我们确保所有服务操作都是幂等性的。这使我们能够在出现暂时性故障时安全地重试操作,而无需担心重复处理。
  2. 实施补偿交易:对于每个操作,我们都实施了相应的补偿操作。这允许我们在任何步骤失败时回滚整个事务。
  3. 使用消息队列:我们使用 Azure 服务总线在 saga 业务流程协调程序和各个服务之间实现可靠的消息传送。这有助于我们处理服务可能暂时不可用的情况。
  4. 实现可观测性:我们使用 Application Insights 来跟踪每个 saga 的进度,事实证明,这对于调试和监视非常有用。
  5. 处理部分故障:我们实施了逻辑来处理补偿事务本身可能失败的情况,确保我们的系统始终达到一致的状态。
  6. 使用超时机制:我们为每个步骤实施了超时,以防止 Sagas 因服务无响应而无限期挂起。

挑战和解决方案

  1. 数据库设计:我们必须重新设计数据库以支持补偿事务。这涉及向相关表添加状态字段,并实施软删除而不是硬删除。
  2. 测试复杂性:测试分布式 Sagas 具有挑战性。我们投资构建了一个全面的集成测试套件,使用 testcontainers-dotnet 来启动我们的服务和数据库的隔离实例。
  3. 错误处理:我们在 ASP.NET Core 管道中实施了自定义错误处理中间件,以确保所有微服务的错误响应一致。
  4. 性能注意事项:随着系统的扩展,我们注意到长时间运行的 Sagas 可能会影响性能。我们通过一致地实现 async/await 模式并使用 TPL Dataflow 进行 CPU 密集型操作来进行优化。

在我们的 .NET Core 8 电子商务应用程序中实现 Saga 模式显著提高了我们管理复杂分布式事务的能力。虽然它引入了一些额外的复杂性,但在数据一致性和系统可靠性方面的好处却是巨大的。

对于考虑 Saga 模式的团队,我建议从一个小型、定义明确的业务流程开始,随着您对该模式及其含义越来越熟悉,逐渐扩展其使用。

请记住,Saga 模式不是灵丹妙药,在实施之前必须仔细考虑您的特定用例和要求。但是,对于微服务架构中的许多分布式事务场景,它可能是一个很好的解决方案。

本文提供了在 .NET Core 8 电子商务应用程序中实现 Saga 模式的真实视角,包括代码示例、关键学习和面临的挑战。它是从高级软件工程师的角度编写的,结合了实践经验和最佳实践。

相关留言评论
昵称:
邮箱:
阅读排行