Skip to content

从单体到微服务的演进

前言

没有哪个架构是"最好的",只有"最适合当前阶段的"。 从单体到微服务不是一步到位的跳跃,而是随着业务规模和团队规模增长,逐步演进的过程。过早拆分微服务和过晚拆分一样危险。

这篇文章会带你学什么?

学完这章后,你将获得:

  • 演进路径:理解从单体到微服务的四个阶段
  • 拆分时机:知道什么时候该拆、什么时候不该拆
  • 拆分策略:掌握按业务域拆分的方法论
  • 通信模式:了解服务间同步和异步通信的选择
  • 数据拆分:理解数据库拆分的挑战和方案
章节内容核心概念
第 1 章架构演进路径单体→模块化→SOA→微服务
第 2 章拆分时机与原则Conway 定律、团队自治
第 3 章拆分策略DDD 限界上下文、绞杀者模式
第 4 章服务通信REST、gRPC、消息队列
第 5 章数据拆分数据库拆分、数据同步

1. 架构演进路径

架构演进不是技术驱动的,而是组织规模驱动的。当团队从 5 人增长到 500 人时,单体架构的协作效率会急剧下降。

阶段架构团队规模特点
起步期单体应用1~10 人所有代码在一个项目中,部署简单
成长期模块化单体10~50 人代码按模块划分,但仍然一起部署
扩张期SOA(面向服务)50~200 人按业务线拆分为粗粒度服务
规模期微服务200+ 人细粒度服务,每个团队独立开发部署
架构演进路径
点击查看每个阶段的架构特点
1
单体架构
2
模块化单体
3
服务化(SOA)
4
微服务架构
单体架构
所有功能打包在一个应用中,共享一个数据库。简单直接,适合早期快速迭代。
用户模块
订单模块
支付模块
商品模块
单体应用(一个进程)
MySQL
适用规模:团队 < 10 人,日活 < 10 万
核心挑战:代码耦合严重,一个模块的 Bug 可能拖垮整个系统

Conway 定律

"设计系统的组织,其产生的架构等同于组织的沟通结构。"——Melvin Conway

简单说:3 个团队做一个系统,最终会变成 3 个服务。架构拆分的本质是组织拆分

反向 Conway 定律:既然组织结构决定了系统架构,那么想要什么样的架构,就先调整成什么样的组织结构。比如你想拆出独立的支付服务,就先组建一个独立的支付团队。很多公司微服务拆分失败,不是技术问题,而是组织没有跟着调整。


2. 什么时候该拆微服务?

不是所有系统都需要微服务。过早拆分会带来不必要的复杂性。

信号说明建议
部署冲突频繁多个团队改同一个代码库,经常冲突考虑拆分
某模块需要独立扩容搜索模块需要 10 倍于其他模块的资源考虑拆分
技术栈需要差异化AI 模块用 Python,主站用 Java考虑拆分
团队 < 10 人沟通成本低,单体足够不要拆
业务还在探索期需求变化快,边界不清晰不要拆
没有 DevOps 能力没有 CI/CD、容器化、监控体系不要拆

3. 拆分策略

3.1 按业务域拆分(DDD 限界上下文)

DDD(领域驱动设计)的限界上下文(Bounded Context)是拆分微服务的最佳指导原则。每个限界上下文对应一个独立的业务域,有自己的数据模型和业务规则。

什么是限界上下文? 同一个词在不同业务域中含义不同。比如"用户"在用户域是指注册信息(姓名、邮箱),在订单域是指下单人(收货地址、支付方式),在推荐域是指行为画像(浏览历史、偏好标签)。限界上下文就是划定一个边界,在这个边界内,术语和模型有明确统一的含义。

┌─────────────┐  ┌─────────────┐  ┌─────────────┐
│   用户域     │  │   订单域     │  │   支付域     │
│             │  │             │  │             │
│ User        │  │ Order       │  │ Payment     │
│ Profile     │  │ OrderItem   │  │ Refund      │
│ Address     │  │ Cart        │  │ Transaction │
│             │  │             │  │             │
│ 用户服务    │  │ 订单服务     │  │ 支付服务    │
└──────┬──────┘  └──────┬──────┘  └──────┬──────┘
       │                │                │
       └────── API 调用 / 事件通信 ───────┘
限界上下文核心实体对应服务
用户域User、Profile、Address用户服务
商品域Product、Category、SKU商品服务
订单域Order、OrderItem订单服务
支付域Payment、Refund支付服务
物流域Shipment、Tracking物流服务

3.2 绞杀者模式(Strangler Fig Pattern)

不要一次性重写整个单体,而是像绞杀榕一样,逐步用新服务替换旧模块:

  1. 在单体外部创建新服务
  2. 通过代理层将部分流量路由到新服务
  3. 验证新服务稳定后,逐步迁移更多流量
  4. 最终完全替换旧模块

4. 服务通信模式

方式协议特点适用场景
RESTHTTP/JSON简单通用,生态好对外 API、CRUD 操作
gRPCHTTP/2 + Protobuf高性能,强类型内部服务间高频调用
消息队列AMQP/Kafka异步解耦,削峰填谷事件通知、异步任务
GraphQLHTTP/JSON客户端按需查询BFF 层、移动端

同步 vs 异步的选择

  • 需要立即返回结果 → 同步(REST/gRPC)
  • 不需要立即返回 → 异步(消息队列)
  • 一个事件触发多个动作 → 异步(发布-订阅)

经验法则:能异步就异步,同步调用链越长,系统越脆弱。


5. 数据拆分:最难的部分

微服务拆分中最痛苦的不是代码拆分,而是数据库拆分。每个服务应该拥有自己的数据库,但这意味着跨服务查询变得困难。

挑战描述解决方案
跨服务 JOIN不能直接 JOIN 两个服务的表API 组合查询、数据冗余
分布式事务跨库事务无法用本地事务Saga、本地消息表
数据一致性多个服务的数据可能暂时不一致最终一致性、事件驱动
数据迁移从共享库迁移到独立库双写过渡、数据同步工具

总结

从单体到微服务是一个渐进的过程,不是一蹴而就的革命。

回顾本章的关键要点:

  1. 演进路径:单体→模块化单体→SOA→微服务,每一步都有明确的驱动力
  2. 拆分时机:团队规模、部署冲突、扩容需求是拆分的信号
  3. 拆分策略:用 DDD 限界上下文指导拆分,用绞杀者模式渐进迁移
  4. 通信选择:能异步就异步,同步调用链越短越好
  5. 数据拆分:最难但最重要,接受最终一致性是关键心态转变

延伸阅读