订单系统到底该怎么建模(四):微服务拆分与聚合边界的终极实践

如果你已经看到第四篇,说明你已经不再只是"写代码",而是在真正思考系统。

前三篇我们做了三件事:

  • 第一篇:搞清楚订单系统有哪些核心模型
  • 第二篇:学会用"聚合"划清边界
  • 第三篇:把 DDD 落地到代码结构

但还有一个绕不开的问题:

当系统变大,必须拆成微服务的时候,这些模型和聚合该怎么落?

这一篇,我们就专门聊这个:微服务拆分 + 聚合边界,到底怎么对齐。


一个常见误区:按"技术"拆服务

很多团队一开始会这么拆:

  • order-service
  • payment-service
  • user-service
  • inventory-service

看起来没问题,但实际很容易变成:

  • 服务之间强依赖
  • 调用链越来越长
  • 改一个功能要动 3 个服务

本质问题是:

拆分依据是"表"或"技术",而不是"业务边界"。


正确的出发点:服务 = 边界上下文(Bounded Context)

在 DDD 里,一个很重要的概念是:

Bounded Context(限界上下文)

你可以简单理解为:

  • 一块完整的业务语义
  • 一套统一的模型
  • 一组一致的规则

而一个微服务,理想情况下应该对应一个 Context。


回到订单系统,我们到底有几个 Context?

不要一上来就拆服务,先划边界。

我们可以这么看:

订单上下文(Order Context)

负责:

  • 创建订单
  • 修改订单
  • 订单状态流转

核心模型:

  • Order
  • OrderItem

支付上下文(Payment Context)

负责:

  • 支付流程
  • 支付状态
  • 对接第三方支付

库存上下文(Inventory Context)

负责:

  • 扣减库存
  • 释放库存
  • 库存锁定

履约上下文(Fulfillment Context)

负责:

  • 发货
  • 物流状态
  • 配送流程

到这里你会发现:

这和第二篇的"聚合划分"是对齐的。

聚合是内部边界,Context 是外部边界。


一个关键结论

一个微服务里可以有多个聚合,但一个聚合绝对不能跨服务。


拆分时最容易犯的错误

错误 1:一个聚合拆到多个服务

比如:

  • Order 在 order-service
  • OrderItem 在 item-service

结果:

  • 强一致没了
  • 调用复杂度暴涨

错误 2:全链路同步调用

下单流程:

  1. 调库存
  2. 调支付
  3. 调物流

问题:

  • 链路长
  • 容错差
  • 一点失败全崩

更合理的方式:事件驱动

下单:

  • 创建订单
  • 发布 OrderCreated

库存:

  • 扣库存 → 发布结果事件

支付:

  • 创建支付 → 发布 PaymentCreated

订单:

  • 监听事件更新状态

一致性怎么选?

强一致:

  • 订单 + 订单项
  • 金额计算

最终一致:

  • 支付
  • 库存
  • 发货

一句话:

跨服务不要强一致。


拆服务的正确顺序

  1. 单体内先做好 DDD
  2. 模块隔离
  3. 再拆服务

否则就是分布式灾难。


写在最后

从单体到微服务,不是技术升级,而是边界能力升级。

如果你走到这一步,其实已经具备系统设计能力了。

相关推荐
Seven972 小时前
【从0到1构建一个ClaudeAgent】并发-后台任务
java
Java面试题总结2 小时前
Java常见面试题(160道)
java·开发语言
浪客川2 小时前
【百例RUST - 007】结构体
java·前端·rust
Rsun045512 小时前
7、Java 装饰器模式从入门到实战
java·开发语言·装饰器模式
黎雁·泠崖2 小时前
二叉树基础精讲(上):树形结构 · 二叉树概念 · 性质 · 遍历 · 基础操作全解析
java·数据结构·算法
biwenjun9992 小时前
chatBI构建思路拆解(重点是元数据增强)
java·数据库·人工智能
Rsun045512 小时前
8、Java 代理模式从入门到实战
java·系统安全·代理模式
人道领域2 小时前
【黑马点评日记02】Redis解决Tomcat集群Session共享问题
java·前端·后端·架构·tomcat·firefox