前言

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

这篇文章会带你学什么?

学完这章后,你将获得:

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

1. 架构演进路径

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

阶段 架构 团队规模 特点
起步期 单体应用 1~10 人 所有代码在一个项目中,部署简单
成长期 模块化单体 10~50 人 代码按模块划分,但仍然一起部署
扩张期 SOA(面向服务) 50~200 人 按业务线拆分为粗粒度服务
规模期 微服务 200+ 人 细粒度服务,每个团队独立开发部署
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. 服务通信模式

方式 协议 特点 适用场景
REST HTTP/JSON 简单通用,生态好 对外 API、CRUD 操作
gRPC HTTP/2 + Protobuf 高性能,强类型 内部服务间高频调用
消息队列 AMQP/Kafka 异步解耦,削峰填谷 事件通知、异步任务
GraphQL HTTP/JSON 客户端按需查询 BFF 层、移动端
同步 vs 异步的选择
  • 需要立即返回结果 → 同步(REST/gRPC)
  • 不需要立即返回 → 异步(消息队列)
  • 一个事件触发多个动作 → 异步(发布-订阅)

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


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

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

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

总结

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

回顾本章的关键要点:

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

延伸阅读

Last updated 26 Apr 2026, 03:21 +0800 . history