Jerry's Blog

Back

核心观点:先写“宪法”(不变量/契约/演进机制),再写“实现”(算法/数据结构/优化)。

先看一张“一页架构宪法图”:

+--------------------------------------------------------------------------------------------------+
|                                   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. 可观测性是系统的“自我意识”#

系统能否演进,取决于变化后能否回答:

  • “我现在是什么状态?”
  • “为什么变成这样?”
  • “影响多大?”
  • “如何回到期望?”

没有自我意识,演进就是盲飞。


设计口号

把系统当作一套“维持不变量的制度”,而不是一堆“实现功能的代码”。 代码会重写;制度(不变量、接口、闭环、扩展点、升级机制、治理)决定系统寿命。


第二部分:宪法——一页纸的架构评审清单#

评审时只问三件事:

  1. 不变量是什么?(哪些东西绝不能破)
  2. 变化放哪儿?(哪些地方必须可插拔、可试验、可回滚)
  3. 怎么演进?(版本/迁移/灰度/回滚/观测/治理是否闭环)

下面是一页版的 “系统设计宪法”:左边是 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 件事

  1. 对象与语义:CRUD 对“什么对象”做“什么语义”的改变。
  2. 访问模式:读多写少?范围查询多?按优先级取?需要排序稳定?
  3. 复杂度预算:热点下的最坏情况?如何降级?

避免写死的 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。
系统设计哲学
https://jerry609.github.io/blog/system-design-philosophy
Author Jerry
Published at January 6, 2026
Comment seems to stuck. Try to refresh?✨