领域驱动设计与微服务事务架构实践

1. 领域驱动设计(DDD)中的事务边界

聚合根的事务一致性

在DDD中,聚合根是事务一致性的基本单元。一个事务应当只修改单个聚合根的状态,跨聚合的操作应通过领域事件实现最终一致性。

// 订单聚合根示例
public class Order {
    private OrderId id;
    private List<OrderItem> items;
    private Money totalAmount;
    
    // 聚合内部保持强一致性
    public void addItem(Product product, int quantity) {
        // 业务规则校验
        if (items.size() >= MAX_ITEMS) {
            throw new BusinessException("Exceed max items limit");
        }
        
        OrderItem item = new OrderItem(product, quantity);
        items.add(item);
        totalAmount = calculateTotal();
    }
}

实践建议

  1. 保持聚合尽量小(通常不超过10个对象)
  2. 通过唯一标识引用其他聚合而非直接对象引用
  3. 聚合方法应实现完整的业务规则校验

领域事件与最终一致性

领域事件是实现跨聚合一致性的关键机制:

图1

事件存储实现示例

public class DomainEventPublisher {
    @Transactional
    public void publish(DomainEvent event) {
        eventStore.save(event); // 与业务操作同一事务
        messageQueue.send(event); // 可能失败但可重试
    }
}

实践建议

  1. 事件应包含足够信息重建状态
  2. 实现幂等的事件处理器
  3. 监控事件处理延迟

2. 微服务事务模式

Saga模式实现

Saga将长事务拆分为多个本地事务,通过补偿操作回滚:

图2

编排式Saga示例

public class OrderSaga {
    public void execute(Order order) {
        try {
            paymentService.charge(order);
            inventoryService.reserve(order);
        } catch (Exception e) {
            // 逆向操作
            paymentService.refund(order);
            inventoryService.cancelReservation(order);
            throw e;
        }
    }
}

实践建议

  1. 为每个Saga步骤设计明确的补偿操作
  2. 记录Saga执行日志用于故障恢复
  3. 设置合理的超时时间

TCC补偿事务

Try-Confirm-Cancel模式实现:

// 库存服务TCC接口
public interface InventoryTccService {
    @PostMapping("/tryReserve")
    boolean tryReserve(@RequestBody TccRequest request);
    
    @PostMapping("/confirmReserve")
    boolean confirmReserve(@RequestBody TccRequest request);
    
    @PostMapping("/cancelReserve")
    boolean cancelReserve(@RequestBody TccRequest request);
}

实践建议

  1. Try阶段应预留资源但不执行业务
  2. 实现幂等的Confirm/Cancel操作
  3. 增加定时任务处理悬挂操作

本地消息表

可靠消息的本地事务方案:

CREATE TABLE outgoing_messages (
    id BIGINT PRIMARY KEY,
    biz_id VARCHAR(64),
    content TEXT,
    status VARCHAR(20),
    created_time DATETIME,
    INDEX idx_status (status)
);

处理流程

  1. 业务操作与消息插入同事务
  2. 定时任务扫描未发送消息
  3. 消息服务确认消费成功

3. CQRS架构下的事务分离

CQRS(Command Query Responsibility Segregation)将读写模型分离:

图3

实现方案对比

方案一致性复杂度适用场景
同步更新强一致金融核心系统
异步事件最终一致大多数业务
定时同步弱一致报表分析

实践建议

  1. 写模型侧重业务规则验证
  2. 读模型优化查询性能
  3. 根据业务需求选择同步策略

总结对比

模式一致性性能复杂度适用场景
聚合事务强一致单个微服务内
Saga最终一致跨服务业务流程
TCC最终一致资源预留场景
本地消息表最终一致异步可靠消息

架构选择原则

  1. 优先考虑业务需求而非技术一致性
  2. 能接受最终一致的场景不追求强一致
  3. 监控比完美的事务设计更重要

通过合理组合这些模式,可以构建既满足业务需求又保持良好性能的分布式系统架构。

添加新评论