# 模式是系统会呈现的形状

软件架构模式速成课。17 种已知的系统形状——Layered、Hexagonal、Microservices、Event-driven、CQRS、Saga 等等——每一种都有英文名、一张图、一张“问题 → 思路 → 例子 → 代价”卡片,以及和其他模式的关联。最后附一页纸的全部模式速查表。

- **Author:** Fedor Chishchin
- **Level:** intro
- **Reading time:** ~30 分钟阅读
- **Published:** 2026-06-02
- **Source:** https://fedorthinks.com/zh/learn/architecture-patterns-express

---

## 1. 什么是模式

模式是对一个在成千上万个系统里反复出现的问题的、经过验证的答案。每个模式都有名字——而且几乎总是英文名,人们在文档里搜的、面试里聊的,都是这个名字。

### 模式是一个答案的名字,不是一条规则

> 下棋时你不会每盘都重新发明开局。你认出"这是西西里防御"——于是已经知道它大致会通往哪里。

**架构模式(architectural pattern)** = 反复出现的问题 + 经过验证的解决形状 + 已知的代价。当你说"服务需要对别处发生的事情做出反应",这已经是一个被解决、被命名的问题——**Event-driven architecture** 模式。懂这套目录,意味着你不再重新发明,而是开始做选择。

### 架构模式 ≠ 设计模式

> 设计模式是你怎么摆放一个房间里的家具。架构模式是整栋房子的平面图。

**设计模式(design patterns)**——Factory、Observer、Strategy——活在一个模块的代码内部。**架构模式**决定系统里有哪些大"盒子"、它们之间有哪些连线:什么被单独部署、谁和谁对话、数据住在哪里。这门课讲的是平面图,不是家具。

### 地图:六组 17 个模式

> 地铁线路图:先看清整条线路,再一站一站地坐。

这门课的所有模式分成六组。每组回答一个问题:怎么组织单个应用、依赖指向哪里、怎么切分系统、各部分怎么通信、怎么在数据里保存真相,以及罕见问题需要哪些形状。

_Diagram: 六组模式——第 2–7 章依次讲解。_

### 怎么读每个模式

> 护照:每本的栏目都一样,所以很容易比较。

接下来每个模式都是同样的结构:**英文名**(记住它——这就是术语)、一个生活中的画面、**一张图**,以及一张**卡片**,包含这些栏目:_问题_(哪里痛)、_思路_(怎么解决)、_例子_、_代价_(你要付出什么)、_何时使用_,以及和其他模式的*关联*。最重要的规则:**不存在最好的模式,只有合适的模式**,而每个模式都有一张账单,要在签字之前读明白。

> **在伸手去拿一个模式之前:** "这个形状解决的是哪个反复出现的问题——而我是不是真的有这个问题?"

> 你不该挑那个出名的模式。你该挑那个你付得起代价的模式。

## 2. 组织单个应用

大多数系统起步时都是单个可部署的应用。最初三个模式讲的是怎么安排它的内部,让它不至于变成一团烂泥。

### Layered Architecture —— 分层架构

> 一家餐厅:大堂接单,厨房做菜,储藏室存货。服务员不下厨,厨师不跑地窖——每个人只和下面那一层打交道。

最常见的模式。代码被切成一层层横向的**层(layers)**,请求从上往下穿过它们。每一层只知道它下面那一层。

_Diagram: 请求逐层往下走:controller → service → repository → 数据库。_

#### Layered Architecture (分层架构, n-tier)

- **问题:** 所有代码堆成一团:改界面会弄坏数据库访问。
- **思路:** 把代码按楼层摆放:表现层、业务逻辑、数据访问、数据库。
- **例子:** Web 应用:`Controller` 调 `Service`,`Service` 调 `Repository`,`Repository` 打到 Postgres。
- **代价:** 所有东西作为一个整体部署;一个小改动 = 重新部署整个应用。
- **何时使用:** 几乎总是可以作为单个应用的起步形状。
- **关联:** 是 **Modular Monolith** 的基础;层内部常常会用到 **Hexagonal**。

### Modular Monolith —— 模块化单体

> 一栋公寓楼:一个屋顶、一个大门,但每套公寓有自己的墙和门。没人穿过邻居的卧室去走楼梯。

仍然是一个应用,但内部按业务含义切成一个个**模块(modules)**——计费、商品目录、账户。模块之间只通过公开接口对话,不碰别人的表。

_Diagram: 一个应用,内部有结实的墙:模块之间只通过公开接口对话。_

#### Modular Monolith (模块化单体)

- **问题:** 单体变成"一大团泥巴":什么都依赖什么。
- **思路:** 按业务模块切分,接口清晰,但作为一个整体部署。
- **例子:** `catalog` 模块只调用 `billing` 的公开函数,而不是它的表。
- **代价:** 需要守住边界的纪律(如果不用工具检查,边界很容易被打破)。
- **何时使用:** **几乎对所有人都是正确的默认选项**——有微服务的清晰,没有网络的麻烦。
- **关联:** 自然地**长成 Microservices**:需要时把某个模块抽出去变成服务。

### MVC / MVVM —— 让屏幕离脑子远一点

> 一座剧场:剧本、演员和导演、舞台和灯光,是不同的活儿。换布景不用重写整出戏。

这些模式在**界面**和**数据与规则**之间立起一道墙,这样改变某样东西*长什么样*,不会弄坏它*做什么*。

_Diagram: MVC:用户 → Controller → Model(数据和规则)→ View(看到的东西)。_

#### MVC / MVVM (Model–View–Controller / Model–View–ViewModel)

- **问题:** 逻辑散落在各个界面里;改设计 = 重写规则。
- **思路:** **Model** 是数据和规则,**View** 是显示,**Controller**(或 **ViewModel**)是两者之间的黏合剂。
- **例子:** Django 和 Rails 基于 MVC;移动应用和富 web 应用基于 MVVM,由 ViewModel 持有屏幕状态。
- **代价:** 界面一大,"黏合剂"就会膨胀;要留意别让逻辑漏进 View。
- **何时使用:** 任何有界面的应用。
- **关联:** 这就是用在 UI 上的 **Layered** 分层。

> **检验一个健康单体应用的方法:** "我能不能改它长什么样、或者换掉数据库,而不必碰那些业务规则?"

> 单体不等于一团乱。没有内部隔墙的单体,才是。

## 3. 依赖的方向

两个模式,同一个想法:业务规则在中心,对 framework、数据库和 web 一无所知。所有技术性的东西都在外面,接到核心上。

### Hexagonal Architecture —— 端口与适配器

> 一台游戏机有标准接口。游戏不在乎你插的是手柄、方向盘还是街机摇杆——它只读"输入"。

装着业务逻辑的核心声明一组**端口(ports)**——像"保存订单"或"扣款"这样的接口。外面的**适配器(adapters)**针对具体技术实现这些端口。**Driving adapters** 调用核心(HTTP API、CLI、测试),**driven adapters** 被核心调用(数据库、支付、邮件)。

_Diagram: 核心声明端口;适配器从外面接进来——换掉它们,核心不会察觉。_

#### Hexagonal Architecture (Ports and Adapters, 六边形架构)

- **问题:** 业务逻辑长进了 framework 和数据库里——没法测试,也没法改。
- **思路:** 核心只和端口(接口)对话;技术住在适配器里。
- **例子:** 端口 `OrderRepository`:生产环境用 Postgres 适配器,测试里用一个内存列表。
- **代价:** 更多接口和文件;对一个小小的 CRUD 来说是多余的。
- **何时使用:** 有真正的业务规则,而且它们要比所用的技术活得更久。
- **关联:** **Clean / Onion 是同一个想法**,只是画成了圆圈。

### Clean / Onion Architecture —— 依赖一律指向内

> 一颗洋葱:心在正中,外面裹着一层层。剥掉外皮不会伤到心——而心并不依赖外皮。

同样的原则,画成一圈圈同心圆。中心是**实体(entities)**,外面一圈是**用例(use cases)**,再外面是适配器,最外层是 framework 和数据库。核心规则是 **dependency rule**:每一支依赖箭头都指向中心。

_Diagram: Clean / Onion:外圈依赖内圈,永远不会反过来。_

#### Clean Architecture / Onion Architecture (整洁架构 / 洋葱架构)

- **问题:** 换 framework 或数据库,就得重写业务逻辑。
- **思路:** Dependency rule:内圈不从外圈 import 任何东西。
- **例子:** "金额超过 1 万的发票需要审批"这条规则,是一个普通的 class,不 import web framework 或 ORM。
- **代价:** 更多的层,以及层与层之间的数据映射。
- **何时使用:** 规则复杂、生命周期很长的产品。
- **关联:** 是 **Hexagonal** 的双胞胎;常常住在 **Modular Monolith** 的模块内部。

> **依赖方向测试:** "如果今晚我把 web framework 删了,我得重写多少业务逻辑?"

> Framework 是细节。把它当墙纸看待,而不是地基。

## 4. 拆成多个部分

到了某种规模——负载的,或者团队数量的——一个应用就撑不住了。这些模式把系统切成独立的部分,作为交换,塞给你一张网络,连同它所有的故障。

### Microservices —— 微服务

> 一座美食广场:每个摊位有自己的厨房、菜单和收银台。披萨摊忙起来就多加两个厨师;沙拉摊不需要。

系统被拆成一个个小**服务(services)**:每个拥有一项业务能力和**自己的数据库**,单独部署、单独伸缩。服务之间通过网络对话——HTTP 或消息总线。

_Diagram: 每个服务有自己的部署和数据库;它们之间是网络。_

#### Microservices (微服务(前身是 SOA))

- **问题:** 很多团队在同一份代码里互相干扰;系统各部分的负载极不均匀。
- **思路:** 独立的服务,各自的数据库,各自部署。
- **例子:** `orders`、`inventory`、`delivery` 三个服务;黑五那天只伸缩订单和支付。
- **代价:** **分布式系统**:网络延迟、服务之间没有简单的事务、运维和调试都很复杂。
- **何时使用:** 大团队、不均匀的负载。对一个五个人的创业公司来说是杀鸡用牛刀。
- **关联:** 从 **Modular Monolith** 长出来;通过 **Event-driven** 和 **Queues** 通信;跨服务的操作需要 **Saga**。

### Serverless —— 按需运行的函数

> 与其养一辆闲着的车,不如叫出租车,只在计价器跑着的时候付钱。

你写一些小**函数(functions)**,云在事件发生时运行它们,自己从零伸缩到上千个副本再缩回去,按每次运行收费。

_Diagram: 事件 → 函数需要跑几次就跑几次 → 结果。按运行次数付费。_

#### Serverless (FaaS, Functions as a Service)

- **问题:** 服务器闲着也要花钱,而负载是一阵一阵来的。
- **思路:** 代码只在事件发生时运行;伸缩交给云。
- **例子:** 图片上传到存储 → 一个函数生成缩略图 → 两次上传之间什么都不运行。
- **代价:** **Cold start**(首次运行的延迟)、运行时间限制、被云厂商绑定。
- **何时使用:** 断断续续、由事件触发的活儿:处理文件、webhook、定时任务。
- **关联:** 天然和 **Event-driven** 搭配。

> **在你拆分之前:** "我拆分,是因为负载或团队真的需要——还是因为'微服务'听起来很资深?"

> 分布式系统把函数调用变成网络调用。它们每一个都可能失败。

## 5. 各部分怎么对话

一旦部分不止一个,架构就大半在它们之间的连线里了。它们怎么对话,决定了它们怎么出故障。

### Request–Response —— 问完就等

> 在柜台点单:你问,你站着等,拿到咖啡才往前走。

客户端发出**请求(request)**,然后**等待响应(response)**。这是**同步**通信:REST、gRPC、一次数据库查询。

_Diagram: 服务器干活时,客户端被阻塞,一直在等。_

#### Request–Response (请求-响应, 同步调用)

- **问题:** 要继续往下走,现在就需要一个答案。
- **思路:** 调用 → 等结果 → 继续。
- **例子:** 结账时调用支付 API,等待确认。
- **代价:** **时间上的耦合**:服务器慢了或宕了,调用方也跟着卡住。
- **何时使用:** 默认选项——当你真的需要立刻拿到答案时。
- **关联:** 和异步的 **Event-driven**、**Queues** 正好相反。

### Event-driven Architecture —— 宣布它,让监听者各自反应

> 一间新闻编辑室:新闻一出,体育、天气、广告各自做出反应。播报员不等他们,甚至不知道谁在听。

组件不去调用别人,而是发布一个**事件(event)**——一个已经发生的事实:"OrderPlaced"。谁感兴趣,谁就订阅并做出反应。两种形式:**broker**(事件自由地传开)和 **mediator**(由一个协调者按顺序推进各步)。

_Diagram: 服务发布一个事件;邮件、库存和分析各自独立地做出反应。_

#### Event-driven Architecture (事件驱动架构)

- **问题:** 一个服务不得不知道并调用所有关心"某事发生了"的服务。
- **思路:** 发布事实;订阅者自己、各自独立地反应。
- **例子:** "OrderPlaced" → 给客户发邮件、在仓库预留、写入分析。
- **代价:** 流程难以追踪和测试;事件可能来两次,或者顺序错乱。
- **何时使用:** 一个动作引发很多互相独立的反应;副作用很慢。
- **关联:** 运行在 **Queues / Pub-Sub** 之上;是 **Event Sourcing** 和 **Saga** 的基础。

### Message Queue 与 Pub/Sub —— 各部分之间的邮局

> 邮局替你存着信,直到收件人准备好。你把信扔进邮筒就走了;他醒来时再读。

**消息队列(message queue)**或 **pub/sub broker** 站在发送方和接收方之间,这样它们不必同时在线。在队列里,一条消息由一个 **worker** 取走;在 **pub/sub** 里,一条消息会发给所有订阅者。

_Diagram: Producer 放下任务就走;workers 有空时再取任务。_

#### Message Queue / Pub-Sub (消息队列 / 发布-订阅)

- **问题:** 慢活儿拖慢了给用户的响应;负载高峰压垮系统。
- **思路:** 把任务放进队列,稍后按自己的节奏处理。
- **例子:** 一份很重的报表被放进队列(RabbitMQ、Kafka、SQS),worker 在后台生成它,网站保持飞快。
- **代价:** 结果变成延后的;要考虑重试和重复消息。
- **何时使用:** 后台任务、削平高峰、服务之间的通信。
- **关联:** 是 **Event-driven** 和 **Microservices** 的传输层。

### Pipe-and-Filter —— 给数据装一条流水线

> 一条灌装线:洗瓶、灌装、封盖、贴标。每个工位只做一件事,然后把瓶子传下去。

数据流过一串独立的步骤——**过滤器(filters)**,由**管道(pipes)**连接起来。每个 filter 只做一种转换。

_Diagram: 数据依次穿过各个 filter,就像 Unix 管道。_

#### Pipe-and-Filter (管道-过滤器, pipeline)

- **问题:** 复杂的数据处理变成了一个巨大的函数。
- **思路:** 拆成简单的步骤,每一步有输入、有输出。
- **例子:** `grep | sort | uniq`、一个 ETL 作业、一个编译器(分词 → 解析 → 优化 → 生成)。
- **代价:** 当各步需要回头、或者互相商量时,就不太合适。
- **何时使用:** 工作本身是一串清晰的转换。
- **关联:** 各步之间常常用 **Queues** 连接。

> **通信测试:** "如果另一边宕了,调用方该等待、失败,还是照常往下走、稍后再补上?"

> 同步是打电话。异步是写信。

## 6. 围绕数据的模式

这些模式不是关于盒子的,而是关于你怎么写、怎么读、怎么保存那份真相。

### CQRS —— 写模型和读模型分开

> 图书馆有一份用来找书的快速目录,还有一间单独的后屋,把书归档上架。查找为一件事优化,存放为另一件事优化。

**CQRS(Command Query Responsibility Segregation)**把**写模型**——改变数据的**命令(commands)**——和**读模型**——取出数据的**查询(queries)**——分开。每一边都可以单独优化、单独伸缩。

_Diagram: 命令进入写模型,查询走单独的读模型;两者之间做同步。_

#### CQRS (Command Query Responsibility Segregation)

- **问题:** 一个数据模型既不适合复杂的写入,也不适合快速的读取。
- **思路:** 两个模型:写模型带着所有规则,读模型是预先算好的"视图"。
- **例子:** 仪表盘从一个去规范化的视图里读,订单写进一个事务型数据库。
- **代价:** 两个模型要保持同步;读取可能稍有滞后(**eventual consistency**)。
- **何时使用:** 读比写多出好几倍,或者两者形状差别很大。不是默认选项。
- **关联:** **常常和 Event Sourcing 配对**:日志里的事件用来构建读模型。

### Event Sourcing —— 存历史,而不是存状态

> 银行不只存你的余额,而是存下每一笔收入和支出。余额只是它们的总和。丢了余额,按账本重算就行。

不去覆盖当前状态,而是存一条**事件流(event log)**,只往末尾追加。当前状态通过**重放(replay)**事件得到。

_Diagram: 事件日志 → 重放 → 当前状态。_

#### Event Sourcing (事件溯源)

- **问题:** 不仅要知道"现在是什么",还要知道"是怎么走到这一步的"。
- **思路:** 事件日志是真相来源;状态从它计算出来。
- **例子:** 账户:"开户、+100、−30、+5",而不是"余额:75"——完整的审计,还能回答"上周二是什么样?"。
- **代价:** "现在是什么"的查询更难了;事件不能修改——历史是永久的。
- **何时使用:** 金融、审计、复杂的业务流程。
- **关联:** 几乎总是和 **CQRS** 一起用;天然和 **Event-driven** 搭配。

### Saga —— 一个可以倒回去的长操作

> 订一趟旅行:机票、酒店、租车。租车没订成——你就取消酒店和机票。没有一个"全部撤销"的按钮,只能一步一步倒回去。

当一个业务动作要经过好几个各有自己数据库的服务时,没法做成一个共同的事务。**Saga** 是一串**本地事务**;某一步失败时,就运行**补偿动作(compensations)**,撤销前面的步骤。

_Diagram: 第 3 步失败 → 补偿动作按相反顺序撤销第 2 步和第 1 步。_

#### Saga (saga, 带补偿的分布式事务)

- **问题:** 一个操作涉及好几个服务,却没有共同的事务。
- **思路:** 按顺序执行各步,每一步都配一个出错时用的"撤销"步。
- **例子:** 创建订单 → 预留商品 → 扣卡;扣卡失败——释放商品,取消订单。
- **代价:** 每一步都需要补偿;各步之间数据暂时不一致。
- **何时使用:** 横跨 **Microservices** 的业务操作。
- **关联:** 需要 **Microservices**;各步常常通过 **Event-driven** 来协调。

> **数据真相之问:** "source of truth 在哪里——是当前的值,还是产生出它的那段历史?"

> 一个事务是一颗意图的原子。当它横跨多个服务时,你得自己把这颗原子造出来。

## 7. 特殊形状

这些模式是为某一种具体的痛而存在的。当你正好有这种痛时再去拿它们——一秒也别提前。

### Microkernel —— 小核心加插件

> 一把电钻:一个马达,十几个钻头。钻还是那把钻——活儿需要什么就换什么钻头。

一个极简的**核心(core)**提供基础,其余一切都以**插件(plugins)**的形式加入,插件接到核心上,彼此互不依赖。

_Diagram: 核心加可插拔的插件——就像代码编辑器和它的扩展。_

#### Microkernel (Plugin Architecture, 插件架构)

- **问题:** 功能很多,经常变,而且不同客户要的不一样。
- **思路:** 稳定的小核心 + 互相独立的插件。
- **例子:** 带扩展的 VS Code 和浏览器;一个保险系统,地区规则就是一个插件。
- **代价:** 要仔细设计插件 API 和它们的兼容性。
- **何时使用:** 平台型产品,按客户定制。
- **关联:** 插件常常像 **Hexagonal** 那样通过端口接入。

### Space-based Architecture —— 数据放内存,没有瓶颈

> 一座体育场有二十个售票窗口,每个都有自己的一份座位图——而不是只有一个窗口排着长队。

当唯一的数据库在巨大负载下成为瓶颈时,工作被分给许多 **processing units**,每个都把数据放在内存里。内存在它们之间同步(**data grid**),数据稍后再异步写进数据库。

_Diagram: 负载分散到内存里存着数据的节点上;数据库不再是瓶颈。_

#### Space-based Architecture (基于空间的架构(tuple space))

- **问题:** 一个数据库扛不住高峰时的并发负载。
- **思路:** 数据放在多个节点的内存里,节点之间同步,稍后再写数据库。
- **例子:** 限时秒杀,或者一场涌入大量同时出价的在线拍卖。
- **代价:** 非常复杂、非常贵;内存和数据库之间有丢数据的风险。
- **何时使用:** 只在真正巨大、忽高忽低的并发负载下。
- **关联:** 像 **Queues** 一样用到缓存和异步写入。

### Peer-to-Peer —— 没有中心

> 一场百乐餐:每个人既是厨师又是客人。没有餐厅,没有服务员——这群人自己喂饱自己。

节点——**peers**——直接互相通信,没有中心服务器。每个节点同时是客户端和服务器。

_Diagram: 每个节点直接连着其他节点;没有中心服务器。_

#### Peer-to-Peer (P2P, 对等网络)

- **问题:** 中心服务器是一个昂贵又脆弱的单点故障。
- **思路:** 参与者自己在彼此之间分担负载和数据。
- **例子:** BitTorrent:每个下载的人同时也在上传——人越多,网络越强。
- **代价:** 很难保证一致性、安全和控制。
- **何时使用:** 文件分发、区块链、不依赖中心主机的韧性。
- **关联:** 和 **Request–Response** 这类客户端-服务器形状正好相反。

> **冷门模式测试:** "我是不是真的有这个形状当初为之而生的那个罕见问题?"

> 冷门模式是药,不是保健品。冲着确诊的病去吃它。

## 8. 怎么选

模式是一套词汇,不是只能点一道菜的菜单。真实的系统会组合好几种——而最明智的一步,往往是最简单的那一步。

### 模式之间是有关联的

> 一栋房子同时用到承重墙、水管和电线——而不是"唯一正确的那种建筑模式"。

模式不会单独存在。模块化单体会**长成**微服务;微服务**需要**事件、队列和 saga;Hexagonal 和 Clean 是**同一个想法**;CQRS 和 Event Sourcing **成对出现**。

_Diagram: 本课各模式之间的主要关联。_

一个真实的系统,可能对外是一个模块化单体,每个模块里是 Clean Architecture,界面用 Request–Response,慢吞吞的副作用走事件,重活前面挡一个队列。问题不是"哪个模式",而是**"哪些模式,放在哪里"**。

### 从最简单的形状起步

> 你不会为了盖一间小木屋去浇一座体育场的地基。

几乎每个系统都该作为 **Modular Monolith** 起步,并**挣得**它的复杂度。Microservices、CQRS、Event Sourcing、Space-based——都是对规模和团队大小问题的回答,而这些问题你也许永远不会有。**最便宜的分布式系统,是你没造的那个。**

#### 在选一个模式之前

- **这个形状解决的是哪个反复出现的问题?** 用一句话说出来。
- **我现在有这个问题吗**——还是在猜未来?
- **它要花多少代价?** 在延迟、运维、复杂度、金钱上。
- **还能用的最简单的模式是哪个?** 从它开始。
- **我能不能以后再用它**,等痛真的冒出来?

#### 你过度设计了的迹象

- **服务比工程师还多。**
- 一个用户动作要碰到**五个服务和两个队列**。
- **CQRS 或 Event Sourcing** 比读取或审计问题来得还早。
- **团队里没人**能凭记忆把系统画出来。
- 选这个模式,**只因为大公司都这么做**。

## 速查表:全部 17 个模式

### 组织单个应用

- **Layered** (分层, n-tier): 代码按楼层摆放:表现 → 逻辑 → 数据 → 数据库。请求从上往下走。
- **Modular Monolith** (模块化单体): 一个应用,切成接口清晰的模块。最好的默认选项。
- **MVC / MVVM** (Model–View–Controller): 在界面和数据与规则之间立一道墙。

### 依赖的方向

- **Hexagonal** (Ports and Adapters): 核心声明端口,技术通过适配器接入。
- **Clean / Onion** (整洁 / 洋葱): 同心圆,所有依赖都指向中心(dependency rule)。

### 拆成多个部分

- **Microservices** (微服务): 独立的服务,各有数据库和部署。代价是分布式系统。
- **Serverless** (FaaS): 函数由事件触发,云负责伸缩,按运行付费。

### 各部分怎么对话

- **Request–Response** (同步调用): 问完就等答案。简单,但在时间上耦合。
- **Event-driven** (事件驱动): 发布一个事实,订阅者自己做出反应。
- **Message Queue / Pub-Sub** (消息队列): 任务在队列里等着,直到有 worker 空出来。
- **Pipe-and-Filter** (管道-过滤器): 数据穿过一串简单的步骤。

### 数据

- **CQRS** (Command Query Responsibility Segregation): 写和读用不同的模型。
- **Event Sourcing** (事件溯源): 存事件日志;状态就是它的重放结果。
- **Saga** (saga): 跨多个服务的步骤 + 出错时的补偿。

### 特殊形状

- **Microkernel** (插件架构): 小核心加互相独立的插件。
- **Space-based** (内存 data grid): 数据放在多个节点的内存里,数据库不再是瓶颈。
- **Peer-to-Peer** (P2P): 节点直接通信,没有中心。

> 最好的架构,是那个能撑过你真实需求的、最简单的架构——再多一个模式都不要。

速成课结束 · 8 章 · 17 个模式

接下来是实践。每一个模式都能展开成好几本书:Mark Richards 的 _Software Architecture Patterns_、_Fundamentals of Software Architecture_、_Designing Data-Intensive Applications_、_Building Microservices_。但在你采用任何一个模式之前——先说出你的问题。模式是答案;问题才是那个让它配得上的提问。
