微服务拆分精讲 / 第 02 章:拆分原则
第 02 章:拆分原则
好的拆分让服务各司其职,差的拆分制造分布式噩梦。原则决定方向。
2.1 单一职责原则(SRP)
2.1.1 从面向对象到服务设计
单一职责原则(Single Responsibility Principle)源自 Robert C. Martin,原本指一个类应该只有一个引起它变化的原因。在微服务语境下,这个原则演化为:
一个微服务应该只负责一个业务能力(Business Capability)。
❌ 错误理解:按技术层拆分
┌──────────┐ ┌──────────┐ ┌──────────┐
│ 前端服务 │ │ 后端服务 │ │ 数据服务 │
└──────────┘ └──────────┘ └──────────┘
(这不是微服务,这是分布式单体)
✅ 正确理解:按业务能力拆分
┌──────────┐ ┌──────────┐ ┌──────────┐
│ 用户服务 │ │ 订单服务 │ │ 支付服务 │
│ (前端+ │ │ (前端+ │ │ (前端+ │
│ 后端+DB) │ │ 后端+DB) │ │ 后端+DB) │
└──────────┘ └──────────┘ └──────────┘
2.1.2 判断标准
如何判断一个服务是否承担了过多职责?
| 信号 | 说明 |
|---|---|
| 服务名包含 “and” | 如 “OrderAndPaymentService” — 明显违反 SRP |
| 修改一个功能需要改动多处 | 说明职责耦合 |
| 服务的 API 超过 30 个 | 可能需要进一步拆分 |
| 团队中不同人负责不同部分 | 说明业务域不同 |
| 服务启动时间过长 | 可能承载了过多功能 |
2.1.3 业务能力识别
业务能力(Business Capability)是组织为实现其目标所做的事情。识别业务能力的方法:
┌──────────────────────────────────────────────────┐
│ 电商企业业务能力地图 │
├──────────────────────────────────────────────────┤
│ │
│ ┌────────────────┐ ┌────────────────┐ │
│ │ 核心业务能力 │ │ 支撑业务能力 │ │
│ ├────────────────┤ ├────────────────┤ │
│ │ • 用户管理 │ │ • 库存管理 │ │
│ │ • 商品管理 │ │ • 物流管理 │ │
│ │ • 订单管理 │ │ • 客服系统 │ │
│ │ • 支付处理 │ │ • 数据分析 │ │
│ │ • 营销活动 │ │ • 内容管理 │ │
│ └────────────────┘ └────────────────┘ │
│ │
│ ┌────────────────┐ ┌────────────────┐ │
│ │ 通用业务能力 │ │ 管理业务能力 │ │
│ ├────────────────┤ ├────────────────┤ │
│ │ • 通知服务 │ │ • 权限管理 │ │
│ │ • 文件存储 │ │ • 审计日志 │ │
│ │ • 搜索服务 │ │ • 系统配置 │ │
│ └────────────────┘ └────────────────┘ │
└──────────────────────────────────────────────────┘
2.2 业务边界划分
2.2.1 高内聚、低耦合
服务内部的元素应该紧密相关(高内聚),服务之间的依赖应该尽可能少(低耦合)。
高内聚 ✅ 低内聚 ❌
┌───────────────┐ ┌───────────────┐
│ 订单服务 │ │ 订单服务 │
│ │ │ │
│ • 创建订单 │ │ • 创建订单 │
│ • 取消订单 │ │ • 用户注册 │
│ • 查询订单 │ │ • 商品搜索 │
│ • 订单状态管理 │ │ • 支付处理 │
│ • 订单金额计算 │ │ • 订单状态管理 │
└───────────────┘ └───────────────┘
(职责聚焦) (什么都干)
2.2.2 边界识别方法
| 方法 | 描述 | 适用场景 |
|---|---|---|
| 业务流程分析 | 梳理核心业务流程,识别独立的业务步骤 | 流程驱动的系统 |
| 数据关系分析 | 分析实体间关系密度,紧密耦合的实体归为一个服务 | 数据密集型系统 |
| 变更频率分析 | 变更频率相近的功能归为一组 | 迭代频繁的系统 |
| 团队结构分析 | 按团队职责划分服务边界 | 组织结构清晰的场景 |
| DDD 限界上下文 | 使用领域驱动设计识别上下文边界 | 复杂业务领域(详见第 03 章) |
2.2.3 边界划分实例:在线教育平台
┌─────────────────────────────────────────────────────────┐
│ 在线教育平台 - 服务划分 │
├─────────────────────────────────────────────────────────┤
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ 用户服务 │ │ 课程服务 │ │ 学习服务 │ │
│ ├──────────┤ ├──────────┤ ├──────────┤ │
│ │• 注册/登录│ │• 课程管理 │ │• 学习进度 │ │
│ │• 个人信息 │ │• 章节管理 │ │• 笔记管理 │ │
│ │• 学员认证 │ │• 课程分类 │ │• 作业提交 │ │
│ └──────────┘ └──────────┘ └──────────┘ │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ 支付服务 │ │ 直播服务 │ │ 通知服务 │ │
│ ├──────────┤ ├──────────┤ ├──────────┤ │
│ │• 课程购买 │ │• 直播推流 │ │• 站内消息 │ │
│ │• 退款处理 │ │• 录播回放 │ │• 邮件通知 │ │
│ │• 订单管理 │ │• 互动弹幕 │ │• 短信通知 │ │
│ └──────────┘ └──────────┘ └──────────┘ │
└─────────────────────────────────────────────────────────┘
2.3 康威定律(Conway’s Law)
2.3.1 原文
“Any organization that designs a system will produce a design whose structure is a copy of the organization’s communication structure.”
— Melvin Conway, 1967
翻译:设计系统的组织,其产生的设计等同于组织之内、组织之间的沟通结构。
2.3.2 康威定律在微服务中的应用
组织结构 系统架构
┌──────────┐ ┌──────────┐
│ 用户团队 │ │ 用户服务 │
│ (5人) │──────────────────│ │
└──────────┘ └──────────┘
┌──────────┐ ┌──────────┐
│ 交易团队 │ │ 订单服务 │
│ (8人) │──────────────────│ 支付服务 │
└──────────┘ └──────────┘
┌──────────┐ ┌──────────┐
│ 基础设施 │ │ API 网关 │
│ 团队(6人)│──────────────────│ 监控平台 │
└──────────┘ └──────────┘
2.3.3 逆康威定律(Inverse Conway Maneuver)
既然组织结构会影响系统架构,那么我们可以反过来——先设计理想的服务架构,再调整组织结构去匹配它。
传统路径:组织结构 ──决定──▶ 系统架构
逆向路径:理想架构 ──指导──▶ 组织调整
实践方法:
- 设计目标微服务架构
- 按服务边界组建团队
- 每个团队对一个或几个服务端到端负责(You Build It, You Run It)
- 团队规模遵循 Two-Pizza Team(6-10 人)
2.3.4 团队拓扑(Team Topologies)
Matthew Skelton 和 Manuel Pais 在《Team Topologies》一书中提出了四种团队类型:
| 团队类型 | 英文 | 职责 | 与其他团队的交互模式 |
|---|---|---|---|
| 流对齐团队 | Stream-aligned Team | 端到端交付业务价值 | 主要团队类型 |
| 赋能团队 | Enabling Team | 帮助流对齐团队克服技术障碍 | 协作模式 |
| 复杂子系统团队 | Complicated-subsystem Team | 管理需要专业技能的子系统 | X 即服务模式 |
| 平台团队 | Platform Team | 提供内部平台服务 | X 即服务模式 |
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ 用户流团队 │ │ 交易流团队 │ │ 内容流团队 │
│ (Stream) │ │ (Stream) │ │ (Stream) │
└──────┬───────┘ └──────┬───────┘ └──────┬───────┘
│ │ │
▼ ▼ ▼
┌──────────────────────────────────────────────────┐
│ 平台团队 (Platform) │
│ CI/CD · K8s · 监控 · 日志 · 服务发现 │
└──────────────────────────────────────────────────┘
2.4 共享与独立的权衡
2.4.1 可以共享的部分
| 共享内容 | 是否推荐 | 说明 |
|---|---|---|
| 共享代码库 | ❌ 不推荐 | 造成强耦合,独立演进困难 |
| 共享数据库 | ❌ 不推荐 | 违反数据自治原则 |
| 共享库(Library) | ✅ 推荐 | 通用工具库、SDK 可以共享 |
| 共享基础设施 | ✅ 推荐 | K8s 集群、监控、日志平台 |
| 共享 API 契约 | ✅ 推荐 | API Schema、Protocol Buffers |
2.4.2 应该独立的部分
每个服务应该独立拥有:
┌─────────────────────────────────────┐
│ 微服务 │
│ │
│ ┌─────────────────────────────┐ │
│ │ 独立代码库 (Git Repo) │ │
│ ├─────────────────────────────┤ │
│ │ 独立数据库 (Schema/实例) │ │
│ ├─────────────────────────────┤ │
│ │ 独立 CI/CD Pipeline │ │
│ ├─────────────────────────────┤ │
│ │ 独立部署 (独立进程) │ │
│ ├─────────────────────────────┤ │
│ │ 独立监控和告警 │ │
│ ├─────────────────────────────┤ │
│ │ 独立团队负责 │ │
│ └─────────────────────────────┘ │
└─────────────────────────────────────┘
2.5 拆分粒度的把控
2.5.1 粒度评估维度
| 维度 | 过粗(需要拆分) | 适中 | 过细(需要合并) |
|---|---|---|---|
| 代码量 | > 5 万行 | 1-3 万行 | < 1000 行 |
| API 数量 | > 50 个 | 10-30 个 | < 5 个 |
| 团队人数 | > 15 人 | 5-10 人 | 1-2 人 |
| 部署频率 | 月级 | 日/周级 | 极少部署 |
| 数据表 | > 50 张 | 10-20 张 | 1-2 张 |
2.5.2 纳米服务反模式(Nanoservice Anti-pattern)
❌ 纳米服务:拆得过细
┌──┐ ┌──┐ ┌──┐ ┌──┐ ┌──┐ ┌──┐ ┌──┐ ┌──┐
│创│ │验│ │计│ │扣│ │退│ │查│ │取│ │删│
│建│ │证│ │算│ │减│ │款│ │询│ │消│ │除│
│订│ │订│ │金│ │库│ │处│ │订│ │订│ │订│
│单│ │单│ │额│ │存│ │理│ │单│ │单│ │单│
└──┘ └──┘ └──┘ └──┘ └──┘ └──┘ └──┘ └──┘
(每个"服务"只有一个函数,运维成本远超收益)
✅ 合理粒度
┌──────────────────┐ ┌──────────────────┐
│ 订单服务 │ │ 库存服务 │
│ │ │ │
│ • 创建/取消订单 │ │ • 库存扣减/恢复 │
│ • 订单查询 │ │ • 库存查询 │
│ • 金额计算 │ │ • 库存预警 │
│ • 退款处理 │ │ │
└──────────────────┘ └──────────────────┘
2.5.3 “大泥球"识别清单
以下特征表明服务可能需要进一步拆分:
- 服务中有 3 个以上不相关的业务模块
- 不同功能的变更频率差异很大
- 一个功能的 bug 可能影响其他功能
- 团队内部出现"子团队”
- 部署一个功能需要回归测试所有功能
2.6 拆分原则总结
2.6.1 核心原则清单
| # | 原则 | 说明 |
|---|---|---|
| 1 | 单一职责 | 一个服务只负责一个业务能力 |
| 2 | 高内聚 | 服务内部元素紧密关联 |
| 3 | 低耦合 | 服务之间依赖最小化 |
| 4 | 数据自治 | 每个服务拥有自己的数据 |
| 5 | 团队自治 | 团队对服务端到端负责 |
| 6 | 技术自治 | 服务可独立选择技术栈 |
| 7 | 部署自治 | 服务可独立部署和扩缩容 |
| 8 | 故障隔离 | 单个服务故障不影响全局 |
2.6.2 拆分检查清单
在决定拆分一个服务前,逐一检查:
┌─ 是否有明确的业务边界?
│
├─ 是否有独立的数据模型?
│
├─ 是否有独立的团队负责?
│
├─ 是否有不同的扩展需求?
│
├─ 是否有不同的变更频率?
│
├─ 基础设施是否就绪(CI/CD、监控)?
│
└─ 拆分的收益是否大于成本?
│
├─ 全部 "是" → 果断拆分
├─ 大部分 "是" → 规划后拆分
└─ 多数 "否" → 暂不拆分
2.7 业务场景:SaaS 系统的拆分决策
背景:一个企业级 SaaS 项目管理工具,包含项目管理、任务管理、文档协作、团队沟通、报表统计五个模块。
分析过程:
| 模块 | 业务边界 | 数据独立性 | 变更频率 | 扩展需求 | 拆分决策 |
|---|---|---|---|---|---|
| 项目管理 | ✅ 清晰 | ✅ 项目、成员 | 🟡 中 | 🟡 中 | 暂不拆分 |
| 任务管理 | ✅ 清晰 | ✅ 任务、看板 | 🔴 高 | 🔴 高 | 优先拆分 |
| 文档协作 | ✅ 清晰 | ✅ 文档、版本 | 🟡 中 | 🔴 高(存储) | 第二优先 |
| 团队沟通 | ✅ 清晰 | ✅ 消息、频道 | 🔴 高 | 🔴 高(实时) | 第一优先 |
| 报表统计 | ✅ 清晰 | ✅ 聚合数据 | 🟢 低 | 🟡 中 | 后期拆分 |
拆分顺序:团队沟通(实时性要求最高)→ 任务管理(变更最频繁)→ 文档协作(存储扩展需求)→ 报表统计
⚠️ 注意事项
- 不要追求完美划分——边界会随着业务理解的深入而演进
- 避免循环依赖——服务间出现 A→B→C→A 的循环是危险信号
- 警惕共享数据库——如果两个服务必须共享数据库,说明它们可能应该是同一个服务
- 考虑事务边界——需要强事务的功能尽量在同一个服务内
- 命名很重要——好的服务名称(如
OrderService)能清晰传达职责
📖 扩展阅读
- Conway’s Law — Martin Fowler 的详细解释(martinfowler.com/articles/conways-law.html)
- Team Topologies — Matthew Skelton, Manuel Pais — 团队结构与软件架构的关系
- Domain-Driven Design — Eric Evans — 用 DDD 指导服务边界的划分(详见第 03 章)
- The Art of Scalability — Martin Abbott — 可扩展性的系统方法论
- Building Microservices — Sam Newman, Chapter 2: The Evolutionary Architect
本章小结
| 要点 | 说明 |
|---|---|
| 单一职责 | 一个服务 = 一个业务能力 |
| 业务边界 | 高内聚、低耦合是划分的黄金法则 |
| 康威定律 | 组织结构 ≈ 系统架构,用逆康威定律指导组织设计 |
| 粒度把控 | 避免纳米服务,从粗粒度开始逐步细化 |
| 决策依据 | 业务边界 + 数据独立性 + 变更频率 + 团队结构 |
📌 下一章:第 03 章:领域驱动设计 — 用 DDD 的方法论科学地识别服务边界。