架构模式是对系统复杂性来源的不同应对方式。所有架构模式,均可投影到以下稳定维度上。
| 层次 | 定义 | 粒度 | 典型示例 |
|---|---|---|---|
| 架构风格 | 系统的高层次组织方式 | 系统级 | 分层、微服务、事件驱动 |
| 架构模式 | 针对系统级反复出现问题的可复用解决方案 | 跨组件 | CQRS、Saga、API Gateway |
架构模式 = 上下文(Context)+ 问题(Problem)+ 解决方案(Solution) 架构风格 ≈ 解决方案的抽象结构
架构风格关注的是:系统整体组织方式,决定了系统的依赖拓扑与约束条件集,它限定了变更的影响范围、扩展的可能性边界、以及团队组织的协作模式
驱动问题:如何在高吞吐量场景下保持处理步骤的解耦?
历史脉络:早期批处理系统面临的问题——强耦合导致任何步骤变化都影响整体;Unix 管道哲学的启示——ls | grep | wc 的组合智慧;核心洞察——数据流动天然适合并行化,且步骤之间无需共享状态
根本矛盾:高吞吐量需求 vs. 处理步骤间的耦合成本
| 根本问题 | 本质 | 数据流风格的解法 |
|---|---|---|
| 提高吞吐量 | 需要并行化但不想引入复杂同步 | 数据流天然支持流水线并行 |
| 降低节点间的耦合 | 需要修改一个步骤不影响其他步骤 | 只通过数据交互,接口标准化 |
节点间解耦:
数据流风格的本质约束:数据必须流经整个管道
↓
带来了两个不可避免的代价:
1. 因果链断裂 → 调试困难
2. 管道延迟累加 → 实时性差
驱动问题:如何控制复杂系统的认知负担?
历史脉络:单体系统规模扩大后,缺乏结构化组织导致逻辑纠缠——所有逻辑纠缠在一起,无法理解、维护、修改;分而治之的思想起源——将大问题分解为可理解的小问题;核心洞察——层次化调用链使系统可被"逐层理解"
根本矛盾:系统的整体性 vs. 人类逐层理解的分段能力
驱动问题:如何防止业务逻辑被技术细节绑架?
历史脉络:分层架构的困境——层间依赖方向混乱,业务逻辑依赖数据库/UI;核心洞察——依赖方向必须指向稳定,业务不应依赖易变的技术实现
根本矛盾:业务稳定性需求 vs. 技术实现的多变性
同心圆结构,依赖方向指向内层。
+────────────────────────────────────────────────────────────────────+
| Frameworks & Drivers |
| +------------------------------------------------------------+ |
| | Interface Adapters | |
| | +----------------------------------------------------+ | |
| | | Use Cases | | |
| | | +----------------------------------------+ | | |
| | | | | | | |
| | | | Entities | | | |
| | | | (Business Rules) | | | |
| | | | | | | |
| | | +----------------------------------------+ | | |
| | +----------------------------------------------------+ | |
| +------------------------------------------------------------+ |
+────────────────────────────────────────────────────────────────────+
依赖方向: 外层 ──────→ 内层
↓
依赖指向稳定
稳定内核,易变边缘:
整洁架构是分层架构的更严格形式——通过同心圆结构明确了依赖方向必须指向内层,避免逆向依赖。
驱动问题:如何让系统核心保持稳定,同时支持功能的差异化扩展?
历史脉络:操作系统内核设计的经验——最小化内核 + 插件扩展;核心诉求——产品线需求(同一核心 + 不同特性);核心洞察——变化的应被隔离,不变的应被固化
根本矛盾:核心稳定性需求 vs. 功能差异化扩展需求
将难测试部分隔离为简单的实现,让测试不依赖易变部分。是微内核架构实现可测试性的重要手段。
驱动问题:如何在多个构件需要共享数据时避免直接耦合?
历史脉络:直接调用的问题——构件间形成网状耦合;共享数据的启示——围绕数据组织而非调用链组织;核心洞察——中央数据存储作为协调点,构件通过数据间接通信
根本矛盾:数据共享需求 vs. 构件直接耦合的风险
架构模式是在某一风格下,对特定问题的可复用解决方案。
驱动问题:如何在构件之间实现真正的时间解耦?
历史脉络:同步调用的困境——调用方必须等待被调用方完成;GUI 编程的启示——用户操作是事件,响应是事件处理器;核心洞察——状态变化是比调用更原语的事件
根本矛盾:时间解耦 vs 复杂性
有中心协调者
无中心协调者
决定了业务规则的结构化程度,直接影响系统对复杂度的抵抗能力和长期维护成本
关注:业务规则以什么形式存在。
事务脚本的隐含假设是:业务 = 操作序列
驱动问题:如何组织简单的业务逻辑?
历史脉络:简单业务场景——逻辑不复杂,不需要复杂的领域抽象;过程化编程的自然映射——一个请求 = 一个过程;核心洞察——复杂度不高时,最简单的结构就是最好的
适用条件:业务简单、生命周期短、逻辑无复用需求
业务简单时,业务认知本身就是线性操作步骤,无需额外抽象
驱动问题:如何用代码表达业务概念而非技术实现?
历史脉络:贫血模型的问题——业务逻辑散落在服务层,对象只是数据容器;面向对象应该同时包含数据和行为;核心洞察——领域模型是业务概念的软件映射
根本矛盾:业务表达清晰性需求 vs. 技术实现便捷性偏好
领域模型是业务概念结构的同构映射——代码结构与业务结构一致。
通过业务结构的同构映射,使业务复杂性可被结构化地分解和组织
表模块的隐含假设是:业务 = 数据的增删改查。与事务脚本模式一样,都属于过程式思维
架构模式并非静态选择,而是随业务规模、技术环境、团队能力动态演进的产物。
架构演进背后是每阶段核心矛盾的转移:
| 阶段 | 核心矛盾 | 驱动的架构变化 |
|---|---|---|
| 单体 → 分层 | 认知负担 vs 业务复杂度 | 分层解耦 |
| 分层 → 模块化单体 | 部署效率 vs 扩展性需求 | 模块化边界 |
| 单体/分层 → 服务化 | 业务复用 vs 耦合成本 | SOA / ESB |
| 单体 → 微服务 | 迭代速度 vs 团队规模 | 按领域拆分 |
| 同步 → 事件驱动 | 响应实时性 vs 系统耦合 | 异步解耦 |
| 微服务 → 服务网格 | 治理复杂度 vs 业务聚焦 | Sidecar 代理 |
单体架构 → 模块化单体 → 垂直拆分 → 核心域微服务化 → 完整微服务 → 服务网格
触发条件:
核心原则:渐进式演进,避免全量重构
分层架构 → 依赖倒置 → 领域分层 → 整洁架构 → 插件化扩展
触发条件:
核心原则:依赖方向指向稳定,业务不依赖技术
事务脚本 → 领域模型 → 事件溯源 → CQRS → 事件驱动
触发条件:
| 决策点 | 单体/分层 | 微服务 | 事件驱动 |
|---|---|---|---|
| 团队规模 | 小 | 中大型 | 任意规模 |
| 部署频率 | 月级 | 周/天级 | 持续 |
| 扩展需求 | 垂直扩展优先 | 水平扩展优先 | 弹性扩展 |
| 业务复杂度 | 中低 | 中高 | 高 |
| 一致性要求 | 强一致 | 弱一致 | 最终一致 |
| 团队能力要求 | 低 | 高 | 中高 |
业务复杂度低 + 团队小 + 扩展需求低
└──→ 分层架构(默认起点)
业务复杂度高 + 需技术灵活性
└──→ 整洁架构 / 六边形架构
团队规模扩大 + 部署频繁
└──→ 模块化单体(过渡态)
扩展压力大 + 需独立部署
└──→ 微服务架构
高并发 + 需实时响应
└──→ 事件驱动 / 空间架构
核心稳定 + 需差异化扩展
└──→ 微内核架构
| 错误 | 表现 | 后果 |
|---|---|---|
| 跳过中间态 | 直接从单体到微服务 | 分布式复杂度爆发 |
| 过度演进 | 小团队强上微服务 | 治理成本超过收益 |
| 进化不彻底 | 模块化单体但边界模糊 | 仍是单体困境 |
| 技术驱动演进 | 为技术趋势而改造 | 业务价值缺失 |
架构设计不是选模式,而是管理复杂性来源。模式演进是对复杂性来源变化的回应。
特征:系统缺乏可识别结构,模块边界模糊,相互缠绕。
后果:维护成本指数增长,系统脆弱,任何改动都可能引发意外故障。
根源:缺乏正式架构设计,开发者各自为政。
特征:将单体机械拆分为多个服务,但服务间高度耦合。
典型表现:所有服务使用同一套技术栈;服务间调用链过长;部署需要协调多个服务同时发布。
后果:继承分布式的复杂度,未获得分布式的收益。
特征:层次过多,一个请求经过 5+ 层处理。
后果:延迟累加,追踪困难,增加不必要复杂度。
特征:服务边界划出过细,一次业务操作需要客户端发起数十次调用。
后果:用户体验差,网络成为瓶颈。
| 误区 | 特征 | 后果 |
|---|---|---|
| 金锤思维 | 对所有问题套用同一种架构 | 忽视业务场景与团队能力匹配 |
| 过早优化 | 为想象中的扩展需求设计复杂架构 | 初期效率极低,团队被复杂度拖累 |
| 技术惯性 | 新建服务默认复用已有技术栈 | 失去技术多样性带来的灵活性 |
| 手段目标化 | 把"使用某种架构"本身当作目标 | 架构服务于技术趋势而非业务价值 |
| 信号 | 可能对应的反模式 |
|---|---|
| 无法回答"系统如何扩展" | 大泥球 |
| 改动一个服务影响多个服务 | 分布式单体 |
| 简单请求需要多次网络调用 | API 过度细分 |
| 无论场景都用同一种架构 | 金锤思维 |
| 小项目但架构很复杂 | 过早优化 |