大家好,我是程序员柏风,AI 最全的 Vibecoding 学习地图 http://coderoadmap.cn 作者。
架构风格
这一课你将能做到
- 给出一个业务场景,能在 5 分钟内判断适合单体还是微服务,并说出 3 个理由
- 画出本站的分层架构图,并指出每一层的职责和依赖方向
- 解释 Serverless 的适用边界,说出至少一个「不该用 Serverless」的场景
为什么要学
「我们要上微服务」是过去十年最危险的架构决策。太多团队在 5 个人、日活 5000 的时候拆了 20 个服务,然后被分布式事务、链路追踪、发布协调活活拖死。
人话:架构风格是房子的结构类型。平房、楼房、别墅各有各的用途。你不能因为别墅高级就在工地上给工人搭别墅住——平房才是对的。
面试场景:「你们为什么用微服务?」「如果现在重来,你会怎么设计?」——面试官在测你对架构演进和权衡的理解。
先建立图像
四种架构风格的结构对比:
【单体】 【分层】
┌──────────────┐ ┌──────────────┐
│ 一个进程 │ │ Presentation │
│ 所有模块 │ │ ─────────── │
│ 共享数据库 │ │ Business │
└──────────────┘ │ ─────────── │
│ Data Access │
└──────────────┘
【微服务】 【Serverless】
API GW CDN
/ | \ │
Svc1 Svc2 Svc3 FaaS Function
|DB| |DB| |DB| / | \
DB Cache Queue
跟着做
步骤 1:单体架构的模块化
本站阶段一的目录结构,按领域模块化:
com.coderoadmap
├── user // 用户域
│ ├── api // 对外接口(DTO/Controller)
│ ├── domain // 领域对象、领域服务
│ └── infra // DAO、外部调用
├── course // 课程域
│ ├── api
│ ├── domain
│ └── infra
├── order // 订单域
│ ├── api
│ ├── domain
│ └── infra
└── common // 工具类
关键:编译时还是一个 JAR,但代码层面已按域隔离。这是「可拆分的单体」,是微服务的前置条件。
步骤 2:何时拆微服务——决策树
团队人数 ≥ 10?
├─ 否 → 单体(或模块化单体)
└─ 是 → 领域边界是否清晰?
├─ 否 → 先 DDD 梳理边界
└─ 是 → 部署频率差异大?
├─ 否 → 模块化单体
└─ 是 → 微服务
本站推演:
- 团队 3 人:单体 + 模块化,共享数据库
- 团队 15 人:用户、课程、订单三个域独立部署,各配 1-2 人
- 团队 50 人:每个域再细分(课程检索、课程管理、课程推荐)
步骤 3:前端架构风格选型
本站从 SSR 到 SPA 的演进:
| 阶段 | 风格 | 技术 | 原因 |
|---|---|---|---|
| 阶段一 | SSR | Thymeleaf | SEO 友好,开发简单 |
| 阶段二 | 混合 | Nuxt.js SSR | 需要交互性,又要 SEO |
| 阶段三 | SPA + BFF | React + Node BFF | 纯工具站,SEO 次要,体验优先 |
讲清楚要点
- 单体不是贬义词:Airbnb、Shopify 早期都是单体。单体的问题不是「单体」本身,而是「没有边界感的单体」。模块化的单体可以支撑团队到 50 人。
- 微服务的本质是组织问题:康威定律——组织沟通结构会复制到系统架构中。两个团队经常吵架的地方,就是服务边界。
- 分层架构的依赖规则必须严格:上层可以调用下层,下层不能调用上层;同层之间尽量不调用。违反这个规则,分层就形同虚设。
- Serverless 不是银弹:冷启动延迟(Java 可达 10 秒)、执行时长限制(15 分钟)、状态管理困难。适合:事件处理、定时任务、突发流量;不适合:长连接、有状态、延迟敏感。
- SOA 和微服务的区别:SOA 是企业级集成(ESB 总线、重量级协议),微服务是团队级自治(轻量协议、去中心化治理)。微服务可以看作 SOA 的轻量版。
你可能会懵的地方
-
微服务一定要容器化吗? 不一定。微服务是架构风格,容器是部署方式。你可以用传统虚拟机部署微服务,但 K8s 的自动扩缩容和服务发现让微服务的运维成本大幅下降,所以两者经常一起出现。
-
单体和微服务能共存吗? 能,而且常见。本站可以课程服务是微服务,后台管理系统是单体(内部工具,流量低、变更少)。这叫「异构架构」,选择依据是每个子系统的特征。
-
什么是模块化单体? 代码层面按域拆分(多个 Maven module),部署时打成一个包。好处:没有分布式事务,调试简单;坏处:不能独立部署、独立扩容。是单体到微服务的过渡态。
-
前端 BFF 是什么? Backend for Frontend——给前端专门搭一层后端。比如移动端和 PC 端需要的数据结构不同,BFF 分别做适配,避免后端接口被前端需求牵着走。
-
事件驱动架构和微服务是什么关系? 事件驱动是一种通信方式,微服务是一种部署方式。微服务可以用 REST 通信(请求-响应),也可以用事件驱动(异步解耦),还可以混用。
错法对照
| 错法 | 问题 | 正解 |
|---|---|---|
| 5 人团队拆 10 个微服务 | 运维复杂度碾压业务复杂度 | 模块化单体,团队 10 人后再评估 |
| 微服务共享数据库 | 失去独立部署和扩缩容的意义 | 每个服务独立数据库,跨服务用 API 或事件 |
| 分层架构层与层互相调用 | 循环依赖,改一处动全身 | 严格单向依赖,必要时引入防腐层 |
| 所有接口都走 REST | 高性能内部通信不需要 HTTP 开销 | 内部服务用 gRPC,外部暴露 REST |
| Serverless 跑长耗时批处理 | 超时、冷启动、调试困难 | 批处理用传统容器或专门调度系统 |
卡点急救
- 单体代码已经耦合得拆不动:用「绞杀者模式」——新功能用新服务实现,老功能逐步迁移。网关层按路由分发到新旧系统。
- 微服务链路出问题了不知道在哪:必须上分布式追踪(SkyWalking / Jaeger),否则排查成本指数级上升。
- 前端说后端接口字段不对,后端说前端需求太杂:引入 BFF,让前端自己写适配层,后端专注领域接口。
面试常问
-
单体和微服务怎么选? 答题框架:团队规模(康威定律)、领域边界清晰度、部署频率差异、运维能力。反模式:不要为了技术而技术。举例:本站 3 人团队时单体最优;15 人后按域拆服务。金句:「微服务解决的是组织并行度和独立部署,不是性能问题。」
-
什么是康威定律? 组织设计系统时,系统的沟通结构会复制组织的沟通结构。如果两个团队必须紧密协作,他们的服务也会紧密耦合。推论:想拆服务,先拆团队。
-
你们系统的分层是怎么设计的? 按本站举例:Controller(入参校验/路由)→ ApplicationService(用例编排)→ DomainService(跨聚合逻辑)→ Repository(持久化抽象)→ DAO/Mapper(具体实现)。依赖方向严格向下。
自测三问
- 本站从单体到微服务的拆分边界应该按什么维度划分?
- Serverless 的冷启动问题对 Java 应用影响大还是小?为什么?
- 分层架构中,ApplicationService 和 DomainService 的职责区别是什么?
小结一句话
架构风格没有优劣,只有适合与否;单体是大多数人的正确选择,微服务是组织成熟后的自然演进,而清晰的边界意识比选择哪种风格更重要。
延伸
- 《构建演进式架构》(Building Evolutionary Architectures)
- 《微服务设计》(Sam Newman)
- martinfowler.com/articles/microservices.html
- 下一课:数据架构——CAP、ACID 与 NoSQL/数仓选型。