适用读者:要在评审会上回答"为什么不上微服务"的人;被"架构风格对比表"绕晕的人。
前置:S18-J05(设计原则与质量属性)、A04(高可用与需求到架构)、S17(分布式基础)。
覆盖旧文:3103(系统架构概述)、3104(第 2 章 架构设计原则)、3105(第 3 章 质量属性)、3106(第 4 章 分层架构)、3107(第 5 章 SOA)、3108(第 6 章 微服务)、3120(第 18 章 性能优化)、3109(第 7 章 分布式基础,与 A06 分工)、2903(教程总目录)→ 9 篇 / 约 4.4 万字符。
扩展点:E-S18-031(质量属性六维与"可测化"写法)、E-S18-032(五种架构风格的取舍矩阵 + ADR 判据)、E-S18-033(拆分的三个前置条件与四个反例)。
下一篇:S18-A06 · 中间件与分布式。
1. 一句话结论
架构风格不是"先进性"排序,而是质量属性的取舍。单体、分层、SOA、微服务、事件驱动——每种都在"某个属性上换到另一个属性"。说不清"牺牲了什么"的选型,都是抄作业。
出处:
A-3103(概述)、A-3104(原则)、A-3105(质量属性)、A-3106–A-3108(三种风格)。
2. 质量属性六维:必须写成可测句(E-S18-031)
| 属性 | 不可测写法 | 可测写法 |
|---|---|---|
| 性能 | "系统要快" | P99 读延迟 ≤ 200ms(@500 QPS,单请求 3 次 DB 查询) |
| 可用性 | "要高可用" | 月度可用性 ≥ 99.9%(允许 43 分钟停机);单 AZ 故障自动切换 ≤ 60s |
| 可扩展性 | "支持扩展" | 写入量翻 10 倍时,仅通过增加节点即可承载(无 schema 变更) |
| 可维护性 | "代码要好维护" | 新成员在 1 天内能定位任一接口的调用链;单模块变更影响面 ≤ 3 个服务 |
| 安全性 | "要安全" | 全链路鉴权 + 敏感字段加密;越权用例 100% 拒绝(含 IDOR 测试集) |
| 成本 | "要省钱" | 单万次请求成本 ≤ X 元;闲置资源占比 ≤ 15% |
判据:属性之间天然冲突——强一致 ↔ 低延迟、高可用 ↔ 强一致、成本 ↔ 冗余。架构决策的本质是"选出这一版必须保住的两个属性,其余允许降级"。
质量属性场景模板(ATAM 风格):
刺激源:运营在后台批量导入 5 万条订单
刺激:写请求突增 20 倍
制品:订单写入链路(API → 订单服务 → MySQL → ES 同步)
环境:正常运行时(非故障态)
响应:写入排队但接口不超时;同步任务延后处理
响应度量:P99 写入 ≤ 800ms;同步延迟 ≤ 5 分钟;无消息积压 > 10 万
3. 五种风格的取舍矩阵(E-S18-032)
| 风格 | 强项 | 弱项 | 何时该用 | 何时是错配 |
|---|---|---|---|---|
| 单体(分层) | 简单、事务一致、调试容易、部署一次 | 团队并发开发冲突、单点扩容粒度粗 | 团队 <10 人、领域未稳定、MVP | 多团队各自频繁改动同一代码库 |
| 模块化单体 | 保留单体的运维简单 + 边界清晰 | 需要纪律(ArchUnit/包约束) | 多数中型项目的正确起点 | 无边界约束 → 退化为大泥球 |
| SOA(ESB 中心) | 异构系统集成、协议转换 | ESB 成为单点与瓶颈、治理复杂 | 遗留系统多、需协议适配 | 新系统从零建(过度设计) |
| 微服务 | 独立部署、技术异构、故障隔离、按服务扩容 | 分布式事务、链路排障、运维成本、网络不可靠 | 多团队、领域边界清晰、有平台能力 | 团队小 / 无 DevOps / 事务强耦合 |
| 事件驱动 | 解耦、削峰、可回放 | 最终一致、幂等与顺序、可观测性弱 | 高吞吐写入、跨域通知 | 需要强一致读、业务要求同步应答 |
四条硬判据(拆微服务前逐条自问):
① 团队:是否有 ≥2 个能独立交付的团队?(一个团队拆微服务 = 给自己加运维)
② 边界:限界上下文是否稳定?(领域还在变,先做模块化单体)
③ 平台:有无统一日志/追踪/配置/发布/回滚能力?(没有 = 排障地狱)
④ 事务:跨服务写是否可改为"最终一致 + 补偿"?业务方能接受延迟窗口吗?
→ 四条有两条答"否",就不该拆。
ADR 最小模板:
# ADR-007 订单与库存的服务边界
状态:已接受(2026-11)|决策者:架构组
背景:订单创建需扣库存,当前同库同事务;预计 12 个月后写入量增长 8 倍。
决策:拆为订单服务 + 库存服务,跨服务用"预留-确认"两阶段(非强事务)。
替代方案:① 保持同库(拒绝:扩容粒度不足)② 分布式事务框架(拒绝:延迟与运维成本)
后果:+ 独立扩容;+ 故障隔离;− 引入最终一致窗口(≤2s);− 需补偿任务与对账
验收:P99 下单 ≤ 300ms;超卖为 0(对账脚本每小时校验);补偿成功率 ≥ 99.99%
回滚:保留同库双写开关,异常时 1 分钟内切回。
4. 拆分的四个反例(E-S18-033)
| 反例 | 症状 | 根因 |
|---|---|---|
| 按技术分层拆(controller 服务、service 服务) | 一次请求跨 5 个服务 | 拆的是"层"不是"业务能力" |
| 按表拆(每表一服务) | 强耦合、大量 join 变跨服务调用 | 数据边界 ≠ 表边界 |
| 共享数据库的微服务 | 改表要协调 N 个服务 | 边界形同虚设,实为分布式单体 |
| 无平台就拆 | 出故障只能登机器 grep | 缺可观测性与发布能力 |
判据:"分布式单体"是所有拆分失败里最常见的一种——判定法:任一需求的变更是否要同时改 ≥3 个服务且需同步发布?是则你只是把单体拉长成了网络调用。
5. 分层架构的正确用法(3106 的重写)
接口层(Controller/Handler) :协议转换、参数校验、鉴权入口
应用层(Application) :用例编排、事务边界、DTO 转换
领域层(Domain) :实体/值对象/领域服务/不变量
基础设施层(Infrastructure) :仓储实现、外部服务适配、消息
| 常见违规 | 后果 | 守护手段 |
|---|---|---|
| Controller 直接调 Repository | 绕过领域不变量 | 分层依赖检查(ArchUnit,见 S09/S07) |
| 领域层 import 框架注解 | 领域被技术绑定、难测 | 领域层零框架依赖 |
| 应用层承载业务规则 | 规则散落、复用困难 | 规则下沉到领域对象 |
| DTO 直接当领域实体 | 外部变更污染模型 | 显式转换(MapStruct/手写) |
6. 性能优化:先定位再优化(3120)
① 定指标:哪个接口、哪个分位(P99)、目标值
② 分段测量:入口 → 应用 → DB/缓存/外部调用(按耗时占比排序)
③ 找瓶颈:80% 耗时集中在哪一段(通常是 DB 查询或 N+1)
④ 优化手段优先级:索引 → 减少往返(批量/缓存) → 异步化 → 加机器
⑤ 回归验证:同一压测脚本对比,确认只改善了目标分位
反例:先上缓存 → 缓存穿透/雪崩 → 再加多级缓存 → 数据不一致。没测量的优化是在赌博。
7. 自测
- 质量属性六维?为什么必须写成可测句?
- 五种风格各牺牲了什么?四条拆分前置条件?
- "分布式单体"怎么判定?
- 分层架构四层职责与两条常见违规?
- 性能优化的五步顺序?
答案
- 性能/可用/扩展/维护/安全/成本;不可测就无法验收。
- 单体牺牲扩容粒度、微服务牺牲事务与运维简单、事件驱动牺牲一致性读;团队/边界/平台/事务四问。
- 任一需求需同步改 ≥3 服务并一起发布即成立。
- 接口/应用/领域/基础设施;Controller 直调仓储、领域依赖框架。
- 定指标→分段测量→找瓶颈→按优先级优化→回归验证。
8. 下一篇
S18-A06 · 中间件与分布式 —— 缓存三模式与一致性、消息队列的语义与顺序、分库分表与读写分离、容器化的边界、负载均衡算法与云原生形态。