已完成架构风格:单体、SOA 与微服务

约 28 分钟 · 阶段:分布式基石 · 能力:在单体/模块化单体/SOA/微服务间做有依据的形态选择

为什么要学本章

分布式系统本质与挑战 与 CAP、BASE 与一致性模型 讲了分布式问题与数据取舍;本章回答:要不要拆、拆成什么形态。盲目 微服务 会把 CAP、BASE 与一致性模型 中的 CAP、部分失败 成本成倍放大。

学完你能
  • 区分分层单体与模块化单体,并说明 ShopFlow 早期可留在单体内的理由
  • 口述 SOA → ESB → 微服务的演进脉络与各自痛点
  • 用康威定律把服务边界与团队拓扑对齐,并列出「不宜拆微服务」的信号
本章先记住 3 件事
  • 形态是手段:先业务边界与交付能力,再选单体还是微服务;勿为简历拆服务。
  • 模块化单体:在单进程内用模块边界练拆分,往往比「先拆再补边界」便宜。
  • 团队即架构:沟通结构会刻在系统里(康威定律);限界上下文 应与能独立交付的团队大致同构。

分层单体与模块化单体的边界

分层单体(Layered Monolith):按技术层划分包结构,所有业务能力共享同一部署单元与数据库。优点是上手快、本地调试简单、事务在进程内完成;风险是边界模糊时演变成「大泥球」——改订单逻辑可能误触库存表。

典型分层(概念)

分层单体 · 请求自上而下
flowchart TB
  UI[Web / API Controller] --> APP[Application Service]
  APP --> DOM[Domain Model]
  DOM --> INF[Infrastructure / JPA]
  INF --> DB[(单一数据库)]

所有业务共享一个 DB 与一次发布;适合团队小、领域尚在高速试错阶段。

模块化单体(Modular Monolith)

仍在一个进程、一次部署,但按业务能力或限界上下文划分子模块(Maven/Gradle 多模块),模块间通过显式 API 通信,禁止随意跨模块访问对方表。

  • shopflow-order、shopflow-inventory、shopflow-payment 模块,共享 shopflow-app 启动器。
  • 模块内可继续分层;模块间仅暴露接口(Java interface / 应用服务门面)。
  • 为将来拆成独立服务做「排练」:边界清晰后再加网络与注册发现。
大泥球单体
  • 按技术层分包,订单 Service 直接注入库存 Repository
  • 无模块依赖规则,循环依赖普遍
  • 「先上线再说」,领域语言在代码里混杂
模块化单体
  • 按 Order / Inventory / Payment 划模块,跨模块只走公开 API
  • ArchUnit / 模块依赖图约束「inventory 不得依赖 order 内部实体」
  • 单库可多 schema 或表前缀,但所有权按模块划分

代码对比:跨边界访问

java
// 反例:订单服务直接操作库存表
@Service
class OrderService {
  @Autowired InventoryRepository inventoryRepo; // 跨上下文泄漏
  void placeOrder(...) {
    inventoryRepo.decrement(skuId, qty);
  }
}
java
// 推荐:通过 inventory 模块公开门面
@Service
class OrderService {
  private final InventoryFacade inventory;
  void placeOrder(...) {
    inventory.reserve(new ReserveCommand(orderId, skuId, qty));
  }
}

SOA、ESB 与微服务的演进脉络

2000 年代前后,面向服务架构(SOA) 强调将企业能力封装为可复用服务,常配合企业服务总线(ESB) 做路由、转换、编排与集中治理。

演进时间线(简化)

企业架构风格演进
timeline
  title 从集中到分布式的常见路径
  2000s : 分层单体 / 大泥球
  2005-2015 : SOA + ESB 集中编排
  2014+ : 微服务 + 轻量消息总线 / API 网关
  近年 : 模块化单体复兴 + 选择性微服务

不是「微服务取代一切」,而是按组织成熟度在谱系上移动。

SOA + ESB 的典型拓扑

ESB 居中编排
flowchart LR
  O[订单系统] --> ESB[ESB 总线]
  I[库存系统] --> ESB
  P[支付系统] --> ESB
  ESB --> T[转换 / 路由 / 编排规则]

所有集成逻辑汇聚到总线:强大但易成瓶颈与「分布式大泥球」的控制中心。

微服务的关键转向

  • 智能端点, dumb pipe:业务逻辑在服务内;管道尽量简单(HTTP/gRPC、消息中间件),避免 ESB 里堆满业务规则。
  • 去中心化数据:每服务自有数据库(或 schema),不再默认「全企业一个库」。
  • 独立部署:团队拥有从设计到运行的全生命周期(DevOps)。
  • ESB 团队成为变更瓶颈,排期长
  • 编排逻辑藏在配置里,难以测试与版本化
  • 技术栈被总线产品绑定
  • 服务间契约(OpenAPI / 事件 schema)+ 消费者驱动测试
  • API 网关 做横切(路由、鉴权),业务编排尽量在域内
  • Spring Cloud Gateway + 注册发现,替代「胖 ESB」

微服务收益、成本与适用场景

微服务不是「更先进的单体」,而是用运维与组织复杂度交换独立演进能力。下表帮助你在评审会上说清利弊。

维度收益成本 / 风险
交付 团队按服务独立发布,减少「全站回归 2 周」 集成测试、契约测试、环境矩阵变多
技术 可按服务选型(如搜索用 Elasticsearch) 统一可观测、安全基线、依赖治理难度上升
弹性 故障隔离(inventory 挂了不必拖垮整站) 分布式事务、Saga、幂等、链路追踪必须到位
组织 与 康威定律 对齐,责任清晰 需要平台工程、SRE、API 治理投入

场景决策表

信号更倾向说明
团队 < 10 人,领域边界每周变 模块化单体 先固化边界,再付分布式税
3+ 团队并行,发布互相阻塞 微服务(边界已清) 独立部署回报大于集成成本
强一致跨库事务是常态 暂缓拆分或保留单体事务 拆后须 Saga / 2PC,复杂度高
读多写少、可接受最终一致 微服务 + 事件 与 CAP、BASE 与一致性模型 AP 路径一致
ShopFlow 示意

当 Order / Inventory / Payment 由不同小队维护、且库存接口变更每周阻塞订单发布时,拆成三个可部署服务才有明显回报;否则模块化单体 + 清晰模块 API 往往足够。

康威定律与团队拓扑

康威定律(Conway's Law):设计系统的组织,其产生的设计等价于组织内的沟通结构。换言之一一你的架构图最终会像你的组织架构图。

对微服务拆分的含义

  • 若订单与库存由同一小队维护,硬拆成两个远程服务只会增加沟通成本,而不会 magically 变快。
  • 若支付由合规独立团队负责,payment-service 作为独立部署单元更自然。
  • 平台团队提供注册发现、网关、CI 模板,让业务小队专注域逻辑(Team Topologies 中的 Platform / Enabling)。
ShopFlow · 团队与服务对齐(目标态)
flowchart TB
  subgraph teamOrder [订单小队]
    OS[order-service]
  end
  subgraph teamInv [库存小队]
    IS[inventory-service]
  end
  subgraph teamPay [支付小队]
    PS[payment-service]
  end
  subgraph platform [平台小队]
    GW[API Gateway]
    REG[注册中心]
  end
  GW --> OS
  GW --> IS
  OS -->|同步 reserve| IS
  PS -->|PaymentCompleted 事件| OS

服务边界与「能独立决策、独立发布」的团队边界尽量同构;跨团队集成走稳定契约。

反模式:组织未拆,服务先拆

两个团队仍共用一个 backlog,却维护六个微服务 — 变更仍需全员协调,却背上分布式排障成本。这叫分布式单体(领域建模、边界上下文与 API 契约 会进一步约束边界)。

何时不应拆微服务

下列信号出现越多,越应推迟物理拆分,优先模块化单体或合并服务。

  • 边界不清:Order 与 Inventory 实体互相引用,无法一句话说清谁拥有哪张表。
  • 无自动化:没有 CI/CD、容器化、集中日志与链路追踪,却要先上 8 个服务。
  • 事务密集:大量跨模块强一致 ACID 需求,拆后只能上重型分布式事务。
  • 团队过小:5 人维护 12 个服务,人均运维负担超过业务开发。
  • 为技术而拆:「微服务很潮」但流量与组织规模仍适合单体。

渐进路径

  1. 模块化单体 — 在进程内练边界与契约。
  2. 绞杀者(Strangler) — 新能力在新服务,旧模块逐步下线(演进模式、反模式与架构评审 再展开)。
  3. 选择性拆分 — 先拆变化最快或需独立扩缩的上下文(如 Inventory 读多写多)。
先想 10 秒:ShopFlow 只有 6 人,是否应立即拆成 order / inventory / payment 三个独立部署?

通常否:优先模块化单体 + 清晰门面;当发布阻塞或团队分组成熟后再拆。拆早会把 CAP、BASE 与一致性模型 中的 CAP、部分失败成本全部兑现且无人力消化。

下一章进入 领域建模、边界上下文与 API 契约,把「模块/服务边界」落到限界上下文与 OpenAPI。

本章结论

每条对应上一节 h3,用于架构评审前的 30 秒复述。

  • 单体谱系:分层单体按技术分包;模块化单体按业务能力/限界上下文分模块,单进程单部署,是拆微服务前的低成本排练。
  • 演进脉络:SOA+ESB 集中编排易成瓶颈;微服务强调智能端点、简单管道与去中心化数据,Spring Cloud 网关等承担横切而非「胖总线」。
  • 利弊权衡:微服务换独立发布与技术异构,付分布式事务、可观测与集成测试代价;边界未清时收益为负。
  • 康威定律:服务边界应与能独立交付的团队拓扑对齐;组织未拆却服务先拆,往往得到分布式单体。
  • 不宜硬拆:边界模糊、无自动化、事务密集、团队过小或为简历拆服务时,优先模块化单体或绞杀者渐进迁移。

复习与自检

过关清单(勾选会保存在本浏览器)

0 / 5 已勾选

本章速查卡
概念一句
模块化单体单部署,模块间只走公开 API
ESB集中编排,易成瓶颈
微服务独立部署 + 自有数据 + 组织对齐
康威定律架构镜像沟通结构
不宜拆边界糊、无自动化、团队过小
答辩 / 面试口述题
  1. 模块化单体与微服务的边界在哪里?何时从前者演进到后者?
  2. 为什么说「ESB 把集成逻辑集中」在微服务时代常被 Gateway + 域内编排替代?
  3. 举 ShopFlow 一个「不应立即拆微服务」的信号并说明缓解步骤。

下一步:勾选过关清单、完成测验与 Demo;下一章 领域建模、边界上下文与 API 契约 固化限界上下文与 API 契约。

动手练习

用「架构形态决策表」与康威定律,为 ShopFlow(7 人 / 日单 200)写架构选型备忘。

操作步骤

  1. 按 Mermaid「模块化单体模块依赖」画出三模块,标允许依赖(→ api)与禁止依赖(× 跨模块 Entity)。
  2. 填写「单体 vs 微服务决策表」ShopFlow 当前阶段一行:团队规模、部署频率、数据边界,勾选推荐形态。
  3. 用两句话对比 ESB 集中转换 vs Gateway「dumb pipe」在变更谁审批上的差异。

判断练习

  1. 「为用上 K8s,先把 Order 拆成 5 个微服务,团队仍是一个 7 人全栈小队。」违反哪 2 条原则?更稳妥的第一步?

    参考答案

    违反康威定律(组织未拆、服务先拆)与不宜硬拆信号(边界/自动化不足)。第一步:模块化单体 + ArchUnit 约束。

  2. 哪条更像 SOA+ESB 反模式?① Gateway 只路由鉴权 ② 所有 JSON↔XML 转换集中在 ESB ③ 各服务维护 OpenAPI

    参考答案

    答:②。ESB 成为转换与编排瓶颈,变更需总线团队审批;①③ 符合智能端点 + 契约分散维护。

Demo:架构形态与团队拓扑实验室

目录:demos/basics-03-architecture-styles-lab/。验收:团队拓扑表三行与决策表「约束」列已填完。

延伸学习