核心观点:先写“宪法”(不变量/契约/演进机制),再写“实现”(算法/数据结构/优化)。
先看一张“一页架构宪法图”:
+--------------------------------------------------------------------------------------------------+
| System Design "Constitution" |
| (Stable Core + Extensible Edge + Evolution Mechanism) |
+--------------------------------------------------------------------------------------------------+
Users/Clients Contract Layer (API = Constitution)
+-----------------+ +----------------------------------------------+
| CLI / UI / SDK | CRUD Req | API Gateway / API Server |
| (kubectl-like) +----------->| - AuthN/AuthZ/Audit |
+-----------------+ | - Validation/Defaulting/Schema/Versioning |
| - Admission/Policy Hooks (optional) |
+-------------------+--------------------------+
|
| SYNC COMMIT POINT
| (Accepted/Committed)
v
+----------------------------------------------+
| Single Source of Truth (SoT) |
| - Strongly consistent metadata/state |
| - Concurrency control (etag/version) |
+-------------------+--------------------------+
|
watch/events | state changes
(pub/sub-ish) |
v
ASYNC CONVERGENCE (Closed-loop control / Reconcile)
+----------------------------------------------+
| Control Plane |
| Controllers / Schedulers / Reconciler(s) |
| - Observe -> Diff -> Act -> Repeat |
| - Writes desired bindings/updates to SoT |
+-------------------+--------------------------+
|
| desired actions/specs
v
+----------------------------------------------+
| Execution Plane |
| Agents / Workers (kubelet-like) |
| - Idempotent apply |
| - Retries/backoff/timeouts |
+-------------------+--------------------------+
|
| plugin/adapters (change lives here)
+-------------------------+--------------------------+
| | |
v v v
+---------------+ +---------------+ +---------------+
| Runtime Plug | | Network Plug | | Storage Plug |
| (CRI-like) | | (CNI-like) | | (CSI-like) |
+-------+-------+ +-------+-------+ +-------+-------+
\ / /
\ / /
v v v
+-----------------------------------------------------+
| Real World / Infrastructure |
| nodes, containers, net, disks, cloud providers |
+-------------------+---------------------------------+
|
| status/telemetry (feedback)
v
+----------------------------------------------+
| Feedback to SoT (STATUS) |
| - node/pod/job status, heartbeats, etc. |
+----------------------------------------------+
Side Planes (must exist):
+----------------------+ +----------------------+ +----------------------+
| Observability | | Evolution Mechanism | | Governance |
| metrics/logs/trace | | skew/feature gates | | RFC/KEP/review/owner |
| queue lag, converge | | migration/rollback | | deprecation policy |
+----------------------+ +----------------------+ +----------------------+
Where algorithms/data structures live:
- Control plane: queues, priority, scheduling scores, dedup (heaps/maps)
- SoT & query: indexes, pagination strategy, caching (B-tree/LSM-like ideas)
- Execution: idempotency keys, rate limiters, backpressure, retry state machines
(Never leak these as external API promises unless you intend to freeze them.)text读图:同步提交点在「契约层(API)→ SoT」;其余靠控制回路异步收敛。
第一部分:哲学——以“不变量”对抗熵增#
1. 先定义世界观:系统的意义是“维持不变量”#
系统的目的不是“实现功能”,而是在变化、故障、需求冲突里维持少数关键不变量。
- 先写清:什么必须永远成立(安全边界、数据一致性底线、抽象边界、可用性承诺)。
- 其余都应允许变化、试验、替换、删除。
K8s 的不变量:声明式期望状态 + 单一事实来源(API/存储)+ 控制回路收敛。
2. 把“控制”与“执行”分离#
大脑只做决策,四肢只做动作。
演进最怕“把环境差异写进核心”。因此拆成:
- 控制面(Control Plane):定义事实、做决策、做协调,提供一致性与策略入口。
- 执行面(Data/Worker Plane):贴近环境执行动作,允许多实现并行。
K8s 用 API/etcd/控制器/调度器当大脑,用 kubelet/runtime/CNI/CSI 当四肢。
3. 把系统做成“闭环”而不是“流程”#
可演进系统的核心是控制回路:观察 → 比较 → 纠偏 → 再观察。
- 流程(Pipeline)擅长一次性完成;闭环擅长长期运行。
- 闭环天然容错、天然扩展、天然支持渐进迁移。
你设计的不是“做事”,而是“让现实持续逼近期望”。
4. 接口是宪法:内部可以重构,外部必须守约#
演进能力不是写新功能,而是在不背叛用户的前提下重构内部。
- 外部接口要版本化;允许弃用,但必须有规则与迁移工具。
- 内部实现可以替换,但接口层面必须“看起来没变”。
稳定不是不变,而是“变化被约束在可承受的表面之下”。
5. 把变化安置在“插件边缘”,把稳定留在“内核中心”#
先准备一个“变化容器”:
- 哪些东西变化快?(运行时、网络、存储、云厂商、策略)
- 就把它们做成可插拔的扩展点(接口/插件/外部控制器/Webhook)。
- 核心只保留少数通用抽象,不为每个特殊需求长出特例。
演进不是让核心长大,而是让生态在边缘繁荣。
6. 演进必须“可分段”:允许不一致,但要规定边界#
升级总是渐进、异构、带偏斜,所以你需要:
- 版本偏斜策略:谁可以比谁新/旧,允许差多少。
- Feature Gate / Capability Negotiation:让能力在一段时间内共存。
- 分阶段迁移:双写、读旧写新、灰度、回滚。
不能分段升级的系统,本质上是“只能重装”的系统。
7. 把治理当作架构的一部分#
规模化演进不只是技术问题,更是冲突管理问题:
- 谁能改动“宪法”(接口、不变量)?
- 变更需要什么证据(KEP/RFC、测试、兼容性分析)?
- 谁对失败负责,怎么回滚,怎么弃用?
没有治理的架构,会被最短期的需求拉成泥球。
8. 可观测性是系统的“自我意识”#
系统能否演进,取决于变化后能否回答:
- “我现在是什么状态?”
- “为什么变成这样?”
- “影响多大?”
- “如何回到期望?”
没有自我意识,演进就是盲飞。
设计口号
把系统当作一套“维持不变量的制度”,而不是一堆“实现功能的代码”。 代码会重写;制度(不变量、接口、闭环、扩展点、升级机制、治理)决定系统寿命。
第二部分:宪法——一页纸的架构评审清单#
评审时只问三件事:
- 不变量是什么?(哪些东西绝不能破)
- 变化放哪儿?(哪些地方必须可插拔、可试验、可回滚)
- 怎么演进?(版本/迁移/灰度/回滚/观测/治理是否闭环)
下面是一页版的 “系统设计宪法”:左边是 Checklist,右边是 Anti-Patterns。
宪法条款 Checklist(逐条勾选)#
1. 不变量优先#
- 写清楚 3–7 条系统不变量(安全边界 / 一致性底线 / 抽象边界 / 可用性承诺)。
- 明确哪些是“可变的”,哪些是“不可变的”(并写出理由)。
- 给不变量对应的“破坏后果”和“降级策略”。
2. 单一事实来源#
- 系统有且只有一个权威状态来源(Single Source of Truth, SoT),其他都是缓存或派生。
- 状态读写路径清晰:谁能写?写什么?如何校验?如何审计?
- 明确强一致与最终一致的边界(哪些必须强一致,哪些可以延迟收敛)。
3. 控制与执行分离#
- 控制面只做决策/协调;执行面只做动作/反馈。
- 执行面可以异构与替换(不同环境/供应商/实现并存)。
- 控制面不依赖执行面的细节实现(只依赖契约/接口)。
4. 闭环设计(Reconcile)#
- 每个关键能力都能描述成:观察 → 比较 → 纠偏 → 再观察。
- “重试是安全的”(幂等/去重/重放可接受)。
- 失败能收敛:有超时、退避、死信/隔离与人工介入路径。
5. 接口即宪法(API/协议/Schema)#
- 外部接口版本化(versioning),并定义兼容与弃用政策。
- Schema 可演进(可选字段、默认值、向前/向后兼容策略)。
- 行为契约被测试锁定(golden tests / conformance tests)。
6. 变化安置在“边缘扩展点”#
- 定义插件点/扩展点:策略、集成、运行时、存储/网络、调度等。
- 扩展点有隔离与配额(不让插件把核心拖死)。
- 可插拔不等于随意:扩展点也要版本化与契约。
7. 演进机制可分段(升级/迁移/回滚)#
- 支持灰度:新旧组件/新旧能力可并存一段时间。
- 数据/Schema 迁移有计划:双写/读旧写新/分阶段切换。
- 有明确回滚策略(回滚会损失什么?如何补偿?)。
8. 可观测性是第一等公民#
- 关键路径有指标、日志、追踪、事件(能定位“为什么坏了”)。
- 有 SLO/报警策略(不是“有监控就行”)。
- 变更可关联(版本/配置/特性开关)以便回归分析。
9. 安全与多租户从一开始就成立#
- 认证/授权/审计/准入(或策略入口)有统一模型。
- 默认最小权限;敏感操作可审计与可追责。
- 租户隔离边界清晰(资源、网络、数据、控制面操作)。
10. 治理与决策机制写进设计#
- 变更入口明确(RFC/KEP/设计评审标准)。
- 所有权清晰(谁维护、谁值班、谁背锅)。
- 兼容性与升级成本是评审硬门槛(不是“上线后再说”)。
反模式 Anti-Patterns(出现任意一条就要拉警报)#
- 泥球核心:需求都往核心塞,无扩展点,靠 if/else 区分环境。
- 双事实来源:多处状态各自为政,排障靠猜,最终靠重启。
- 流程式系统:一次性 pipeline,无幂等重试,故障放大小修补多。
- 没有版本的接口:随意改 API,无弃用期,系统被旧包袱锁死。
- 不可分段升级:必须全量同版本才能工作,规模越大越难演进。
- 扩展点无约束:插件阻塞关键路径,核心稳定性被外部实现绑架。
- 观测后补:先做功能再补监控,每次演进都是盲飞。
- 安全靠约定:默认管理员权限,无审计,规模化后必出事故。
- 治理缺失:无评审标准,决策债累积比技术债更致命。
第三部分:实现——CRUD 与算法的归位#
增删查改(CRUD)和数据结构/算法不是“实现细节”,而是两层分工:
- CRUD 属于契约层 + 状态层:对外承诺对象/语义/一致性。
- 数据结构/算法属于实现层 + 性能层:用实现与优化兑现契约。
1. CRUD 的归位:从接口语义到权威状态#
接口层:定义对外语义#
- Create:是“创建资源”,还是“提交期望状态”(如 K8s 的 apply)?
- Update:是覆盖、PATCH,还是声明式合并?
- Delete:软删/硬删?异步回收?finalizer/回收期?
- Read:强一致读、读写隔离,还是允许读旧(stale read)?
接口语义决定系统能否演进而不破坏用户。
状态层:落地权威状态(SoT)#
- 哪些字段是 SoT;谁能写;如何校验与审计。
- 并发控制:版本号/ETag/乐观锁/事务边界。
- 删除语义:墓碑、TTL、回收队列、引用完整性。
SoT 设计决定 CRUD 在规模化后会不会变成“双事实来源”的灾难。
链路层:CRUD 在端到端链路中的位置#
逐步写清:谁读谁写,失败怎么重试,如何收敛。
2. 算法与数据结构的归位:从访问模式到性能预算#
性能层:算法必须显性化#
- 关键路径延迟预算(如 P99 50ms)。
- 吞吐/并发/内存/热点/放大效应(N+1 查询、全表扫描)。
- 退化情况:最坏复杂度会不会在生产触发?
很多系统不是功能错,而是某个 O(n) 在 n 变大后把系统拖死。
边界层:实现策略不外泄#
数据结构属于组件内部实现,应封装在边界内:
- 对外只暴露语义(“列出”“筛选”“按优先级调度”)。
- 不把内部结构(链表/堆/索引细节)泄露成对外契约。
验证层:正确性 + 复杂度假设被测试锁定#
- 正确性:排序稳定性、去重、幂等、边界条件。
- 性能回归:数据规模扩大时的基准测试。
3. 元定位:CRUD 是状态机,算法是控制回路的工具#
在闭环系统里:
- CRUD 往往是在改期望状态(desired state),不是命令式“执行动作”。
- 算法/数据结构服务于控制回路:排队、优先级、去重、收敛、调度、回收。
链路:
不变量/契约(承诺什么)→ 访问模式(怎么用)→ 算法/结构(怎么实现)
4. 评审口径:必须写清 vs 避免写死#
必须写清的 3 件事:
- 对象与语义:CRUD 对“什么对象”做“什么语义”的改变。
- 访问模式:读多写少?范围查询多?按优先级取?需要排序稳定?
- 复杂度预算:热点下的最坏情况?如何降级?
避免写死的 1 件事:
- 不要在 API 契约里承诺内部结构的“偶然性质”。
- 例如:返回顺序刚好是某个索引顺序。
- 除非你愿意把“排序规则/稳定性/分页一致性”当作长期承诺。
5. 常见能力 → 典型结构/算法#
| 能力场景 | 典型结构/算法 |
|---|---|
| 资源按优先级处理 | 优先队列/堆(+ 去重 map) |
| 去重/幂等 | 哈希表 + 幂等键/版本号 |
| 范围查询/排序分页 | 有序索引(B-tree/LSM)+ 游标分页 |
| 依赖/编排 | DAG + 拓扑排序 |
| 调度/匹配 | 过滤 + 打分(可插件化) |
| 热点与缓存 | LRU/LFU + 一致性策略 |
这些不需要写进对外 API,但需要体现在性能与退化分析里。
第四部分:落地——可执行的系统设计文档模板#
这是一份可直接复制的系统设计文档骨架,每一节都对应上述“宪法条款”。
系统设计文档骨架(Template)#
文档信息#
- 标题:
- 作者/Owner:
- 评审人:
- 状态:草案 / 评审中 / 已批准 / 已弃用
- 目标发布日期:
- 相关链接:PRD / RFC / 事故复盘 / 竞品分析
1. 摘要(1 页内)#
- 这是什么:用一句话描述解决什么问题。
- 为什么现在要做:触发原因(增长、成本、稳定性、合规等)。
- 核心结论:选了什么方案?不做的代价?关键风险(Top 3)?
2. 背景与问题定义#
- 现状:架构简述、痛点量化(延迟、QPS、故障率)。
- 问题陈述:明确范围(管哪里、不管哪里)、受影响对象。
- 成功标准(SLO):可用性、延迟、成本等红线。
3. 不变量与原则(核心宪法)#
在这写清楚 3–7 条系统不变量。对每条写清:描述、为什么成立、破坏后果、降级策略。
- 示例:Invariant-1 单一事实来源……
4. 需求与范围#
- 功能需求:Must / Should / Could
- 非功能需求:可用性、扩展性、一致性(强/弱)、安全、成本。
- Out of Scope:明确不做的事。
5. 关键场景与链路(真实链路)#
- 主要用户旅程:Step 1 → Step 2… 每步的输入/输出/状态。
- 失败与恢复链路:超时、网络分区时,系统如何收敛/补偿。
6. 架构概览#
- 高层架构图:控制面 vs 执行面。
- 组件职责表:职责、依赖、扩容方式、失败模式。
- 数据流 vs 控制流:哪些链路必须强一致。
7. 数据模型与一致性#
- 权威数据(SoT):存储在哪里、谁能写、如何审计。
- Schema/版本:兼容策略、默认值。
- 一致性模型:并发冲突策略(锁/版本号/乐观并发)。
- 迁移方案:双写/回填顺序,回滚是否丢数据。
8. 接口与扩展点#
- 对外 API:版本、限流、弃用策略。
- 对内事件:Topic、Schema、重放策略。
- 扩展点:插件位置、隔离机制(超时/配额)。
9. 演进与发布策略#
- 版本偏斜:允许组件版本不一致的范围。
- 灰度/Feature Gate:开关控制、回滚触发条件。
- 发布与回滚:发布步骤、数据回滚补偿。
10. 可靠性工程(SRE)#
- SLO:错误预算、报警策略。
- 容量与性能:估算 QPS、依赖限流熔断。
- 灾备:RTO/RPO、备份演练。
11. 可观测性#
- 指标:RED/USE 覆盖。
- 日志:结构化规范。
- 追踪:Trace 采样与关联。
- 审计:关键事件记录。
12. 安全与合规#
- 认证授权、多租户隔离、数据合规。
13. 测试与验收#
- 单元/集成/E2E、回归基线、上线准入条件。
14. 风险、权衡与备选#
- 风险清单:概率、影响、缓解措施。
- 备选方案:为什么不选 A 或 B。