限界上下文与微服务
DDD 不是微服务的前提,但 DDD 可以帮助微服务拆分。
限界上下文 Bounded Context
Section titled “限界上下文 Bounded Context”每个上下文内部可以有自己的模型,同一个词在不同上下文中含义可能不同。
例子——“账户”在不同上下文中的含义:
| 上下文 | “账户”的含义 |
|---|---|
| 用户系统 | 登录账号 |
| 账务系统 | 资金账户 |
| 权限系统 | 身份主体 |
核心域 / 支撑域 / 通用域
Section titled “核心域 / 支撑域 / 通用域”| 分类 | 说明 | 策略 |
|---|---|---|
| 核心域 | 业务竞争力所在,最复杂的部分 | 自建,投入最多资源 |
| 支撑域 | 为核心域服务,但不是核心竞争力 | 自建或外购 |
| 通用域 | 通用能力,大家都需要 | 优先外购或用开源 |
上下文映射 Context Map
Section titled “上下文映射 Context Map”不同限界上下文之间的关系模式:
- 共享内核 Shared Kernel:两个上下文共享部分模型
- 客户-供应商 Customer-Supplier:上游提供,下游消费
- 防腐层 Anti-Corruption Layer:在边界处翻译对方模型,保护自己的领域模型
- 开放主机服务 Open Host Service:上游提供标准化协议
- 各行其道 Conformist:下游直接遵循上游模型
微服务拆分时,优先按限界上下文拆,而不是按数据库表拆。
例子:
- 订单上下文
- 支付上下文
- 账务上下文
- 库存上下文
- 用户上下文
DDD 和 CQRS
Section titled “DDD 和 CQRS”DDD 和 CQRS 可以结合,但不是绑定关系。
CQRS 是命令查询职责分离:Command 处理写入和状态变更,Query 处理查询和展示。
复杂系统中,写模型可以用 DDD 聚合保证一致性,读模型可以按页面或接口需求单独构建,避免用复杂聚合对象做报表查询。
查询列表是否要通过聚合
Section titled “查询列表是否要通过聚合”不一定。聚合适合处理命令和状态变更,不适合复杂查询、报表、分页列表。
查询可以走 read model、QueryService、DTO projection,甚至直接 SQL,只要不绕过领域规则修改状态即可。
DDD 和数据库表是否一一对应
Section titled “DDD 和数据库表是否一一对应”不应该强制一一对应。领域模型表达业务概念,数据库表表达存储结构。一个聚合可能对应多张表,一张表也可能服务于某个读模型。