Skip to content

Microservice or Monolith(微服务还是单体) ​

解决什么问题:怎么判断一个系统应该从单体起步还是直接拆微服务—— 拍脑袋选 = 拆早了运维崩溃、拆晚了耦合到拆不动。 选错了 = 几年回炉重写。

它是什么 ​

Monolith(单体)——一个部署单元、一个进程、一个数据库。所有模块共享同一代码库、同一运行时。

Microservice(微服务)——每个服务独立部署、独立进程、可选独立数据库,服务间通过 API / 消息通信。

这不是二选一——存在中间形态:

1. 单体(Modular Monolith)        ← 推荐起步
2. 单体 + 模块化边界              ← 推荐 10 人团队
3. 部分模块独立部署(绞杀者模式)   ← 推荐过渡
4. 微服务(完整拆分)              ← 推荐 ≥ 50 人 / 多团队

Sam Newman(Building Microservices):"Premature decomposition is a big risk. Most successful microservice extractions started as a modular monolith and were split later."

V2 视角(V2.7 B3 段 5 + B6 段 4):这是 L2 设计层最经典的折衷——没有"哪个绝对好",只有"在你这个规模 / 团队 / 业务下哪个更划算"。

关键属性 ​

属性Modular MonolithMicroservices
部署单元1 个N 个(N 个 BC)
代码库1 个仓库 / 多模块N 个仓库 或 monorepo
数据库1 个每个服务独立 DB(推荐)
通信进程内方法调用HTTP / gRPC / 消息
部署频率一起部署独立部署
故障域1 个(全局故障)N 个(局部故障)
运维成本低高(K8s/服务网格/监控)
团队规模≤ 20 人≥ 50 人
业务成熟度早期 / 探索期稳定期 / 多团队并行

怎么用 ​

场景 1:起步选型决策树 ​

Q1: 团队规模?
├─ ≤ 5 人        → Modular Monolith(必须)
├─ 5-20 人       → Modular Monolith(强烈推荐)
└─ ≥ 50 人       → 继续问

Q2: 业务稳定吗?
├─ 还在探索       → Modular Monolith(先跑通业务)
└─ 稳定 + 多个独立 BU → Microservices

Q3: 部署频率需求?
├─ 周级部署       → Monolith 足够
└─ 日级 / 小时级  → 考虑拆分(按 BC)

Q4: 团队地理分布?
├─ 同城 / 同楼   → Monolith 协作方便
└─ 多城市 / 多时区 → Microservices(解耦协作)

Q5: 性能 / 伸缩粒度?
├─ 整体伸缩      → Monolith
└─ 单模块 10x 伸缩 → Microservices(只扩热的那个)

Vernon 在 IDDD Ch 3 也明确:"在大多数项目中,先用单体起步,等 BC 稳定后再拆分"。

场景 2:Modular Monolith 的工程纪律 ​

V2 B3 段 5 "团队可拥有" 视角:Modular Monolith 成功的关键是强制模块边界——

com.example.app/
├── order/                  ← Order BC 模块
│   ├── domain/             ← 聚合、用例
│   ├── application/        ← 应用服务
│   ├── infrastructure/     ← Adapter
│   └── interfaces/         ← 本模块 Web / API
│
├── payment/                ← Payment BC 模块
│   ├── domain/
│   └── ...
│
└── shared/                 ← 跨 BC 共享(慎用!)
    └── kernel/             ← 共享内核必须明确

纪律工具:

  1. Maven / Gradle 多模块:每个 BC 一个 module,强制依赖方向
  2. ArchUnit 单元测试——禁止 order.domain 依赖 payment.domain
  3. 包私有可见性——BC 内 public,BC 间用专门 Facade
  4. 定期 Event Storming——确保 BC 边界清晰

场景 3:绞杀者模式(Strangler Fig)—— 平滑迁移 ​

从单体拆微服务的标准方法——逐步替换,不重写:

                    ┌──────────┐
   老请求 →  ──→   │  Facade  │  ──→ 老单体
                    │(路由层)  │  ──→ 新服务 A (已迁)
                    │          │  ──→ 新服务 B (已迁)
                    └──────────┘

步骤:

  1. 在入口加 Facade(API 网关 / Nginx / 业务路由层)
  2. 把一个 BC 的流量切到新服务(10% → 50% → 100%)
  3. 老代码里删掉这个 BC 的代码
  4. 重复下一个 BC

SE@G Ch 17:"演化式拆分(Evolutionary Decomposition)"——永远不要一次性拆完。

场景 4:拆分时的反模式 ​

分布式单体(Distributed Monolith)——最常见的拆错:

❌ "微服务" 但:
- 共享同一个数据库
- 用同步 HTTP 调用串成链路
- 一起部署
- 一个服务挂了全链路挂
= 这不是微服务,是"用 RPC 调用的单体",更糟糕

V2 B6 段 5 "折衷的退化":拆分要保证独立部署 + 独立伸缩 + 独立故障域——三个都满足才算真拆开。

场景 5:判断"什么时候该拆" ​

团队规模 × 协作成本 触发拆分的阈值:
- 5 人 → 永远不该拆(运维成本 > 收益)
- 10-20 人 → 看情况(构建慢 → 拆构建;部署耦合 → 拆部署)
- 50 人+ → 必须拆(否则 PR 冲突、部署互锁)

业务演化触发拆分的阈值:
- 一个 BC 的变更频率 > 其它 10x → 拆(让热的独立部署)
- 一个 BC 的伸缩需求 > 其它 10x → 拆(独立扩缩容)
- 多个团队负责不同 BC → 拆(团队边界对齐服务边界)

常见误区 ​

  1. "微服务 = 高级"——错。Monolith 是 90% 系统的正解,过早拆微服务 = 自找麻烦
  2. "拆了微服务就能独立部署"——半对。没拆干净 = 分布式单体,比单体更糟
  3. "先拆微服务再说"——错。先跑通业务 + 识别 BC + 摸清边界,再拆——否则拆出来的 BC 边界也是错的
  4. "微服务必须用 K8s + 服务网格 + 分布式追踪"——错。5 个服务的微服务用 docker-compose 就够。工具按规模来
  5. "一旦单体就永远单体"——错。绞杀者模式 + 演化拆分,随时可以从单体过渡到微服务

关键洞察 ​

"先单体再拆分"是 90% 情况下的正解;"一开始拆"是少数情况下的正解。

选错的核心原因是用技术时髦度代替业务判断—— 微服务是工具,不是目标。

V2 B6 折衷原则:团队规模、业务稳定度、部署频率、伸缩需求 四个变量决定起点。"Microservice or Monolith" 不是信仰选择, 是工程权衡。判错标志 = 团队人数 5 但在跑 K8s 集群 / 团队 100 但还在一个 500 万行单体里。

相关链接 ​

从名家方法论与工程化思路中蒸馏出自己的工程体系。