架构演进决策树
凌晨两点,某电商公司的 CTO 被一条告警叫醒:订单服务超时,所有新订单都无法创建。他紧急登录监控后台,发现问题根源是「商品搜索」模块的一个慢查询,把整个数据库连接池打满了。
但他面临一个尴尬的现实:他的团队只有 8 个人,系统代码量 30 万行。他不确定该不该在这个时间点做微服务拆分,也不确定有没有能力承担拆分后的运维成本。
这是一个很典型的问题:什么时候该演进?如何判断演进的时机和方法?
这篇文章提供一套决策树框架,帮助你在正确的时机做正确的架构选择。
决策树的四个核心维度
架构演进不是拍脑袋决定,而是基于客观指标的判断。四个维度帮你量化现状:
维度一:团队规模
团队规模决定了协作模式的上限。Fred Brooks 在《人月神话》中指出,沟通成本随团队人数指数增长。
graph TD
A[团队规模] --> B{5人以下}
A --> C{5-15人}
A --> D{15-50人}
A --> E{50人以上}
B --> F[单体架构]
C --> G[模块化单体]
D --> H[初步拆分]
E --> I[微服务/中台]
维度二:代码量与复杂度
代码量是技术债务的显性指标,但不是唯一指标。复杂度往往比代码量更关键。
代码量评估标准:
| 规模 | 代码行数 | 业务复杂度 | 推荐行动 |
| --- | --- | --- | --- |
| 小型 | `<` 5 万行 | 单业务域 | 保持单体,优化代码质量 |
| 中型 | 5~20 万行 | 2~3 个业务域 | 模块化拆分,数据层隔离 |
| 大型 | 20~50 万行 | 多业务域 | 按业务边界拆分服务 |
| 超大型 | `>` 50 万行 | 跨多个产品线 | 微服务 + 中台 |
警告:代码量不是拆分依据,领域边界清晰度才是。
维度三:业务复杂度
业务复杂度包括:业务流程数量、跨团队依赖、数据一致性要求。
维度四:技术债务
技术债务会放大所有其他问题。在高技术债务的系统中,即使业务规模不大,也可能需要演进。
技术债务评估清单:
如果超过 3 个问题回答「是」,技术债务已经是瓶颈,演进需要提速。
不同阶段的关键指标
架构演进不是一次性事件,而是连续的过程。每个阶段有对应的关键指标。
阶段一:单体架构
关键指标监控:
发布周期:每周发布 1~2 次
故障恢复时间(MTTR):`<` 1 小时
资源利用率:30%~50%
团队协作:日常 code review
警示信号:
- 发布窗口成为瓶颈
- 一个 bug 导致整个系统回滚
- 数据库成为唯一瓶颈
阶段二:模块化单体
模块化单体是单体架构到微服务的过渡态。核心是在物理上保持单体,但在逻辑上划分清晰的边界。
模块化标准:
✅ 模块间通过接口通信,不直接调用内部实现
✅ 每个模块有独立的数据访问层
✅ 模块可以独立测试
✅ 模块间的共享代码降到最低
❌ 模块间直接引用对方类
❌ 跨模块的事务控制
❌ 共享数据库表(多个模块读写同一张表)
阶段三:服务化拆分
服务化拆分需要评估基础设施就绪程度:
基础设施就绪清单:
[ ] 服务注册与发现(Consul / Nacos / Eureka)
[ ] API 网关(Kong / APISIX / Spring Cloud Gateway)
[ ] 分布式配置中心(Nacos Config / Apollo)
[ ] 链路追踪(SkyWalking / Jaeger / Zipkin)
[ ] 集中日志(ELK / Loki)
[ ] 容器化部署(Docker + Kubernetes)
[ ] CI/CD 流水线
如果基础设施不完善,拆分后的问题会比拆分前更多。
阶段四:微服务/中台
微服务不是终点,而是另一种复杂度。高可用、多语言、技术演进能力,是微服务的主要收益。
微服务成熟度评估:
| 能力 | 初级 | 中级 | 高级 |
| --- | --- | --- | --- |
| 部署 | 手动部署 | 半自动 | 全自动 CD |
| 监控 | 基础监控 | 链路追踪 | 业务监控 + SLO |
| 治理 | 无 | 限流熔断 | 自适应限流 |
| 弹性 | 手动扩容 | HPA | VPA + 预测扩容 |
微服务的代价:
- 服务间网络延迟
- 分布式事务复杂性
- 运维成本(通常是单体的 3~5 倍)
演进的前提条件
架构演进需要「万事俱备」才能降低风险。
基础设施就绪
不要在基础设施不完善时做拆分。拆分后暴露的问题,往往不是业务问题,而是运维问题。
最低基础设施要求:
1. 容器化:Docker 镜像标准化
2. 编排:Kubernetes 或等效平台
3. 监控:至少覆盖 CPU、内存、QPS、延迟
4. 日志:集中收集,至少能按 trace ID 检索
5. 告警:关键指标 7x24 告警
没有这些基础设施,拆分等于自找麻烦。
团队能力匹配
架构复杂度需要对应的团队能力来支撑。
能力错配的风险
一个只有 CRUD 经验的团队,上微服务后会发生什么?
- 不知道怎么排查网络问题
- 不会处理分布式事务
- 监控告警不知道看什么
- 服务挂了不知道怎么回滚
结果是:系统稳定性反而下降。
业务边界清晰
拆分失败的案例,80% 源于业务边界不清晰。
边界不清晰的后果:
场景:拆分「用户模块」和「订单模块」
错误边界:
┌─────────────┐ ┌─────────────┐
│ 用户模块 │ ── │ 订单模块 │
│ (注册/登录) │ │ (创建/取消) │
└──────┬──────┘ └──────┬──────┘
│ │
│ ┌───────────┐ │
└──►│ 用户画像 │◄──┘
│ (用户模块 │
│ 还是订单 │
│ 模块管?) │
└───────────┘
正确做法:
先画清楚「用户画像」属于谁,边界清晰后再拆分。
演进的风险评估
每次演进都是一次风险操作。风险评估和回退方案是演进的必备项。
风险矩阵
风险评估模板:
| 风险项 | 发生概率 | 影响程度 | 应对策略 |
| --- | --- | --- | --- |
| 服务间调用失败 | 高 | 高 | 熔断降级 |
| 分布式事务不一致 | 高 | 高 | Saga/TCC |
| 拆分后性能下降 | 中 | 高 | 灰度验证 |
| 团队能力不足 | 中 | 中 | 培训/引入专家 |
| 基础设施不匹配 | 低 | 高 | 先完善基础设施 |
核心原则:每次演进的风险敞口不超过团队可承受范围。
回退方案
没有回退方案的演进是裸奔。
回退方案设计:
方案一:蓝绿回退
- 保持旧版本实例不动
- 新版本出问题,立即切换流量到旧版本
- 适合:服务完全替换的场景
方案二:特性开关回退
- 使用 feature flag 控制功能开关
- 新功能有问题,关闭开关即可
- 适合:同一服务的渐进式改造
方案三:数据回退
- 保留旧数据库写入接口
- 新服务写入时同步旧数据
- 回退时切换写入目标
- 适合:数据层迁移场景
案例:从 5 人团队电商系统看架构选择
某小型电商公司,团队 5 人,代码量 8 万行,主营母婴用品电商。
阶段一:单体架构(0~1 年)
现状:
- 团队 5 人,协作流畅
- 代码量 8 万行,结构尚可
- 业务稳定,增长缓慢
决策:保持单体架构
行动项:
1. 模块化代码结构(按业务域划分包)
2. 引入单元测试,提高覆盖率到 60%
3. 搭建基础监控(Prometheus + Grafana)
理由:
这个阶段瓶颈是「如何快速开发」,不是「如何大规模协作」。
微服务带来的运维成本,是 5 人团队无法承受的。
阶段二:模块化单体(1~2 年)
现状:
- 团队扩到 8 人,出现协作摩擦
- 业务增长 3 倍,开始有性能压力
- 代码量 15 万行,技术债务累积
决策:模块化拆分,不拆分服务
行动项:
1. 按领域划分模块(用户、商品、订单、支付)
2. 模块间通过接口通信,移除直接引用
3. 每个模块独立数据访问层
4. 引入灰度发布能力
理由:
团队还没有运维微服务的能力。
模块化可以解决 80% 的协作问题。
阶段三:服务化拆分(2~3 年)
现状:
- 团队扩到 20 人,按业务线分工
- 双十一流量是平时的 10 倍
- 某些模块成为独立瓶颈
决策:按业务边界拆分核心服务
行动项:
1. 引入 Kubernetes
2. 拆分「商品服务」和「搜索服务」(热点模块)
3. 引入 API 网关
4. 搭建链路追踪
理由:
基础设施已经就绪,团队能力跟上。
拆分先从热点模块开始,降低风险。
总结
架构演进决策的核心是「匹配」:
演进时机 = 业务需求驱动 AND 基础设施就绪 AND 团队能力匹配
三缺一,风险倍增。
三缺二,不建议演进。
判断框架回顾:
- 团队规模:5 人以下单体,15 人以上考虑拆分
- 代码量:20 万行以上需要模块化,50 万行以上需要服务化
- 业务复杂度:跨团队依赖强,需要服务边界清晰
- 技术债务:债务高企会放大所有问题
前提条件:
- 基础设施就绪(监控、日志、容器化、CI/CD)
- 团队能力匹配(分布式理解、DevOps 能力)
- 业务边界清晰(边界不清晰是拆分失败的头号原因)
风险管理:
- 每次演进有回退方案
- 灰度验证是安全迁移的关键
- 渐进式演进优于大步快跑
思考题
问题 1:某创业公司 CTO 觉得微服务是「先进架构」,想在团队只有 3 个人时就上微服务。这样做可能面临什么问题?
参考答案
3 人团队上微服务,主要面临以下问题:
- 运维成本过高:3 人团队需要维护服务注册、配置中心、链路追踪、CI/CD 等基础设施,运维负担可能超过开发本身
- 协作成本增加:微服务适合大团队并行开发,3 人团队本身体量小,拆分后反而增加协调成本
- 问题排查复杂:分布式调用链路长,排查问题需要链路追踪工具,3 人团队可能缺乏相关经验
- 基础设施投入大:K8s 集群、CI/CD 流水线等都需要人力维护,ROI 太低
建议:3 人团队保持单体,专注业务开发。等团队规模超过 10 人、业务复杂度明显上升时,再考虑模块化或拆分。
问题 2:在演进过程中,如何判断「现在拆分」的时机已经成熟,而不是「可以再等等」?
参考答案
几个客观指标帮助判断拆分时机:
- 团队瓶颈明显:发布频率成为业务迭代的瓶颈(如每周只能发布一次)
- 协作成本可量化:多人开发导致的代码冲突频率、集成测试时间有明确数据
- 基础设施就绪:K8s、监控、CI/CD 等基础设施已经可用
- 业务边界清晰:通过 DDD 建模或业务流程分析,边界已经明确
- 团队能力匹配:至少有 1~2 人有分布式系统经验
如果 3 个以上指标满足,可以开始考虑拆分。
问题 3:如果演进后发现拆分决策错误(边界划错了),应该怎么办?
参考答案
拆分边界错误是常见的坑,处理方式取决于错误程度:
轻度错误(边界模糊,但还能工作):
- 通过 API 网关做服务聚合,掩盖边界问题
- 逐步重构,不追求一次性解决
中度错误(两个服务强耦合,频繁调用):
- 引入防腐层(ACL),将调用关系限制在接口层
- 考虑合并这两个服务
重度错误(循环依赖、数据一致性无法保证):
- 制定合并计划,逐步将流量切回单体
- 承认试错成本,不要硬撑
- 合并后再重新分析边界
关键原则:边界错了就合并,不要为了「面子」继续撑。合并的代价远低于持续维护一个错误架构。