Pipeline + Saga 分布式扩展规范

Pipeline + Saga 分布式扩展规范(V1.0)

0. 架构结论先行(必须统一认知)

Pipeline 解决"单服务内的确定性执行顺序"
Saga 解决"跨服务副作用的一致性与补偿"

Pipeline ≠ Saga
Pipeline + Saga = 分布式可逆业务内核


1. 为什么 ERP 必须引入 Saga(而不是分布式事务)

1.1 ERP 的真实约束

  • 跨服务(库存 / 财务 / 结算 / 物流)

  • 高并发

  • 外部系统不可控

  • 允许"最终一致",不允许"状态错乱"

1.2 为什么不用 XA / 2PC

问题 结果
性能
外部系统
云原生
可观测

ERP 的一致性来自"可补偿",不是"强锁定"


2. 总体架构模型(升级后)

复制代码
┌──────────────────────────┐
│ ScopedValue               │
│ trace / tenant / operator │
└────────────▲─────────────┘
             │
┌────────────┴─────────────┐
│ Local Pipeline            │  ← 单服务内顺序 + 本地回滚
└────────────▲─────────────┘
             │
┌────────────┴─────────────┐
│ Saga Orchestrator         │  ← 跨服务编排
└────────────▲─────────────┘
             │
┌────────────┴─────────────┐
│ Remote Service Pipelines  │  ← 各服务独立 Pipeline
└──────────────────────────┘

3. 核心设计原则(强制)

3.1 单服务内:Pipeline

  • 强类型 I → O

  • 明确顺序

  • 本地 RollbackAction

3.2 跨服务:Saga Step

  • 明确 Forward / Compensate

  • 允许异步

  • 允许失败重试


4. Saga 的最小抽象模型(标准)

4.1 SagaStep 定义

复制代码
public interface SagaStep<C> {

    void forward(C context);

    void compensate(C context);
}

4.2 SagaContext(跨服务业务上下文)

复制代码
public record SagaContext(
    String sagaId,
    String docNo
) {}

约束:

  • 只能放 全局业务标识

  • 禁止放中间结果

  • 禁止放服务私有对象


5. Pipeline × Saga 的结合点(关键)

5.1 每个 SagaStep 内部 = 一个 Local Pipeline

复制代码
SagaStep
 ├─ Pipeline (本服务)
 │   ├─ 校验
 │   ├─ 执行
 │   └─ 本地 rollbackActions
 └─ compensate()

5.2 示例:库存服务 SagaStep

复制代码
public class StockSagaStep implements SagaStep<SagaContext> {

    public void forward(SagaContext ctx) {
        executionPipeline.execute(
            new ExecuteInput(ctx.docNo())
        );
    }

    public void compensate(SagaContext ctx) {
        rollbackPipeline.execute(
            new RollbackInput(ctx.docNo())
        );
    }
}

⚠️ compensate 不是简单反调用

独立设计的补偿语义


6. Saga Orchestrator(编排器)

6.1 顺序 Saga(ERP 最常见)

复制代码
public class SagaOrchestrator {

    private final List<SagaStep<SagaContext>> steps;

    public void execute(SagaContext ctx) {
        List<SagaStep<SagaContext>> executed = new ArrayList<>();

        try {
            for (SagaStep step : steps) {
                step.forward(ctx);
                executed.add(step);
            }
        } catch (Exception e) {
            rollback(executed, ctx);
            throw e;
        }
    }

    private void rollback(
        List<SagaStep<SagaContext>> steps,
        SagaContext ctx
    ) {
        for (int i = steps.size() - 1; i >= 0; i--) {
            steps.get(i).compensate(ctx);
        }
    }
}

6.2 并行 Saga(可选进阶)

  • 用于:

    • 多仓库存冻结

    • 多账户预扣

  • 要求:

    • 幂等

    • 独立补偿


7. ERP 场景完整示例(销售出库)

复制代码
销售出库 Saga
 ├─ 库存服务(扣库存)
 ├─ 财务服务(记应收)
 ├─ 物流服务(生成发货单)

失败场景:

  • 物流失败

    → 回滚:财务冲销 → 库存回补


8. Saga + ScopedValue 的边界(再次强调)

ScopedValue 允许:

  • traceId

  • tenantId

  • operator

ScopedValue 禁止:

  • saga 执行状态

  • step 执行结果

  • 是否已补偿

Saga 的状态必须持久化,而不是隐式存在


9. Saga 状态持久化(强烈推荐)

9.1 SagaInstance 表(示意)

字段 说明
saga_id 全局唯一
doc_no 单据号
status RUNNING / COMPENSATING / DONE
current_step 当前步骤
created_at 创建时间

9.2 SagaStepInstance 表

字段 说明
saga_id 关联
step_name 库存 / 财务
status DONE / FAILED / COMPENSATED
retry_count 重试次数

10. 失败与重试策略(ERP 必须)

场景 策略
forward 失败 触发补偿
compensate 失败 重试 + 人工介入
服务不可达 延迟重试
重复请求 幂等拒绝

11. 与三 Pipeline 的最终映射关系

层级 职责
审核 Pipeline 是否允许启动 Saga
执行 Pipeline SagaStep.forward
回滚 Pipeline SagaStep.compensate

12. 架构红线(必须写进规范)

🚫 禁止一个 SagaStep 内跨多个业务域

🚫 禁止 SagaContext 承载中间业务数据

🚫 禁止用消息最终一致掩盖不可回滚设计


13. 一句话架构总结(非常重要)

Pipeline 保证"一步不乱",
Saga 保证"走错能退"。

ERP 的核心竞争力,
来自"复杂业务的可逆性"。

相关推荐
初次攀爬者2 天前
ZooKeeper 实现分布式锁的两种方式
分布式·后端·zookeeper
断手当码农3 天前
Redis 实现分布式锁的三种方式
数据库·redis·分布式
初次攀爬者3 天前
Redis分布式锁实现的三种方式-基于setnx,lua脚本和Redisson
redis·分布式·后端
业精于勤_荒于稀3 天前
物流订单系统99.99%可用性全链路容灾体系落地操作手册
分布式
Asher05093 天前
Hadoop核心技术与实战指南
大数据·hadoop·分布式
凉凉的知识库3 天前
Go中的零值与空值,你搞懂了么?
分布式·面试·go
?Anita Zhang3 天前
联邦学习实战:如何在分布式场景下构建隐私保护机器学习模型
人工智能·分布式·机器学习
tony3653 天前
pytorch分布式训练解释
人工智能·pytorch·分布式
2501_933329553 天前
技术深度拆解:Infoseek媒体发布系统的分布式架构与自动化实现
分布式·架构·媒体
星辰_mya4 天前
消息队列遇到Producer发送慢
分布式·kafka