应用Strangler模式将遗留系统分解为微服务:第一部分 – CodesCode

“探索如何将传统系统分解为POS/e-commerce系统的微服务架构的领域特定实例”

许多来源提供了微服务的一般解释,但缺乏领域特定的例子。新手或那些不确定从何处开始的人可能会发现将他们的旧系统转换成微服务架构是具有挑战性的。本指南主要面向那些在开始迁移工作方面感到困惑的个人,并提供业务特定的示例来帮助理解这个过程。

还有另一种模式我想谈谈 – 窒息器模式这是一种用于逐步将旧系统转换为新系统的迁移模式,以最小化风险。

我们以传统的杂货计费系统为例。现在是时候升级到微服务架构以发挥其好处了。

窒息器模式是一种在逐步开发新系统的同时逐步废弃旧系统的模式。这样,用户可以更早地开始使用新的系统,而不必等待整个系统迁移完成。

在这篇第一篇文章中,我将重点介绍杂货店所需的微服务。例如,假设您目前拥有一个杂货店的传统系统,并且有兴趣将其升级为微服务架构并迁移到云端。

杂货店传统系统概述

首先,一个在线杂货店可能具有以下模块:

  1. 购物车服务
  2. 支付处理服务和退款
  3. 库存管理服务:产品数量在售出时应减少,在订单退款时应增加。

按照窒息器模式,您应该能够在继续使用其他模块的同时,用新的微服务替换一个模块,直到新服务准备就绪。

在这里,您可以首先用新的服务替换购物车。由于购物车服务依赖于支付处理服务,您还需要开发后者。

假设我们将逐步开发这些服务。为了演示目的,我只关注以上三个服务。但在实际情况中,您可能需要下面所示的其他服务才能完成杂货店的整个电子商务网站:

现在让我们考虑每个服务所需的基本模型类和操作。

对于购物车服务,您将需要以下模型类和操作:产品、产品类别、添加到购物车的项目、购物车和订单。它可以组织如下:

购物车服务

public class Product{    public Guid Id { get; set; }    public string Name { get; set; }    public decimal Price { get; set; }    public int StockQuantity { get; set; }    public Category ProductCategory { get; set; }}public class Category{    public Guid Id { get; set; }    public string Name { get; set; }}public class ShoppingCartItem{    public Product Product { get; set; }    public int Quantity { get; set; }}public class ShoppingCart{    public Guid Id { get; set; }    public List<ShoppingCartItem> Items { get; set; }    public Customer Customer { get; set; }    public DateTime CreatedAt { get; set; }}public class Order{    public Guid Id { get; set; }    public List<ShoppingCartItem> Items { get; set; }    public Customer Customer { get; set; }    public decimal TotalAmount { get; set; }    public DateTime CreatedAt { get; set; }}

理想情况下,您应该创建一个共享项目来存放所有模型和接口。首先确定必要的模型和操作非常重要。

在考虑客户在购物车中可以执行的操作时,通常只涉及一个主要操作CreateOrder,用于将项目添加到购物车。然而,其他操作,如付款处理、退款和库存调整,应作为单独的微服务实施。这种模块化方法使得管理业务过程的不同方面更加灵活和可扩展。

public class BillingService : IBillingService{	public Order CreateOrder(Customer customer, List<ShoppingCartItem> items)    {        return new Order        {            Id = Guid.NewGuid(), //创建新的订单号            Items = items,            Customer = customer,            TotalAmount = CalculateTotalAmount(items),            CreatedAt = DateTime.Now        };    }    private decimal CalculateTotalAmount(List<ShoppingCartItem> items)    {        decimal totalAmount = 0;        foreach (var item in items)        {            totalAmount += item.Product.Price * item.Quantity;        }        return totalAmount;    }}

在共享项目中,理想情况下,您需要为 IBillingService 创建一个接口。接口应如下所示:

public interface IBillingService{   public Order CreateOrder(Customer customer, List<ShoppingCartItem> items);}

现在,您可以对 CreateOrder 操作进行单元测试。

在真实世界中,常见的做法是创建一个 IBillingRepository 来将订单保存到数据库中。这个仓储应该包括存储订单到数据库的方法,或者您可以选择使用下游服务来处理订单创建过程。

在本讨论中,我不会涉及用户认证安全、托管、监控、代理和其他相关主题,因为它们是不同的主题。我的主要关注点仍然是按照您的具体要求定制的微服务设计方面。

创建完购物车后,下一步是处理客户付款。让我们继续创建 Payment Service 项目及其相关模型。

付款处理服务

public class Payment{    public Guid Id { get; set; }    public decimal Amount { get; set; }    public PaymentStatus Status { get; set; }    public DateTime PaymentDate { get; set; }    public PaymentMethod PaymentMethod { get; set; }}public enum PaymentStatus{    Pending,    Approved,    Declined,}public enum PaymentMethod{    CreditCard,    DebitCard,    PayPal,}public class Receipt{    public Guid Id { get; set; }    public Order Order { get; set; }    public decimal TotalAmount { get; set; }    public DateTime IssuedDate { get; set; }}public class PaymentService : IPaymentService{    private PaymentGateway paymentGateway;    public PaymentService()    {        this.paymentGateway = new PaymentGateway();    }    public Payment MakePayment(decimal amount, PaymentMethod paymentMethod, string paymentDetails)    {        // In a real system, you would handle the payment details and validation before calling the payment gateway.        return paymentGateway.ProcessPayment(amount, paymentMethod, paymentDetails);    }}public class ReceiptService : IReceiptService{    public Receipt GenerateReceipt(Order order)    {        var receipt = new Receipt        {            Id = Guid.NewGuid(),            Order = order,            TotalAmount = order.TotalAmount,            IssuedDate = DateTime.Now        };        return receipt;    }}

在这个 Service 项目中,您需要创建和实现以下接口:

public Interface IPaymentService{    public Payment MakePayment(decimal amount, PaymentMethod paymentMethod, string paymentDetails); }public Interface IReceiptService{    public Receipt GenerateReceipt(Order order);}public Interface IPaymentRepository{   public Payment ProcessPayment(decimal amount, PaymentMethod paymentMethod, string paymentDetails)} public class PaymentGateway : IPaymentRepository{    public Payment ProcessPayment(decimal amount, PaymentMethod paymentMethod, string paymentDetails)    {        // In a real system, you would handle the payment details and validation before calling the payment gateway.        // 在真实的系统中,您将在调用支付网关前处理支付明细和验证。        var payment = new Payment        {            Id = Guid.NewGuid(),            Amount = amount,            Status = PaymentStatus.Pending,            PaymentDate = DateTime.Now,            PaymentMethod = paymentMethod        };        // In a real system, you would connect to a payment gateway and process the payment, updating the payment status accordingly.        // For example, you might use an external payment processing library or API to handle the transaction.        // Simulating a successful payment here for demonstration purposes.        // 在真实的系统中,您将连接到支付网关并处理支付,更新支付状态。        // 例如,您可以使用外部支付处理库或API来处理交易。        // 在这里模拟成功的付款,用于演示目的。        payment.Status = PaymentStatus.Approved;        return payment;    }}

所有这些服务都创建好后,我们可以很容易地使用新的系统摘除购物车(假设您还同时创建了新的用户界面)。

接下来,我们必须解决订单下达后的库存管理问题。库存管理服务负责在创建采购订单时进行补货。这个服务项目的结构如下:

库存管理服务

public class Product{    public Guid Id { get; set; }    public string Name { get; set; }    public decimal Price { get; set; }    public int QuantityInStock { get; set; }    public Category ProductCategory { get; set; }}public class Category{    public Guid Id { get; set; }    public string Name { get; set; }}public class Supplier{    public Guid Id { get; set; }    public string Name { get; set; }    public string ContactEmail { get; set; }}public class PurchaseOrder{    public Guid Id { get; set; }    public Supplier Supplier { get; set; }    public List<PurchaseOrderItem> Items { get; set; }    public DateTime OrderDate { get; set; }    public bool IsReceived { get; set; }}public class PurchaseOrderItem{    public Product Product { get; set; }    public int QuantityOrdered { get; set; }    public decimal UnitPrice { get; set; }}public interface IInventoryManagementService{    void ReceivePurchaseOrder(PurchaseOrder purchaseOrder);    void SellProduct(Product product, int quantitySold);}public class InventoryManagementService : IInventoryManagementService{    public void ReceivePurchaseOrder(PurchaseOrder purchaseOrder)    {        if (purchaseOrder.IsReceived)        {            throw new InvalidOperationException("The order is already placed.");        }        foreach (var item in purchaseOrder.Items)        {            item.Product.QuantityInStock += item.QuantityOrdered;        }        purchaseOrder.IsReceived = true;    }    public void SellProduct(Product product, int quantitySold)    {        if (product.QuantityInStock < quantitySold)        {            throw new InvalidOperationException("Item not in stock.");        }        product.QuantityInStock -= quantitySold;    }}

正如我所提到的,这篇指南主要是为那些在开始他们的迁移工作中感到困惑的人而设计的,并提供了一些业务特定的例子来帮助理解整个过程。

我相信这篇文章对于如何在微服务架构中开始你的迁移项目提供了有价值的见解。如果你正在开发一个杂货店或任何在线购物车系统,这些信息对你来说应该特别有用。希望你可以从这里开始。在我的下一篇文章中,我将提供另一个与特定领域相关的例子,当然你也可以在其他地方探索更多关于微服务的一般信息。


Leave a Reply

Your email address will not be published. Required fields are marked *