02 · 架构师的思考框架
上一章说「架构是在取舍中做重要决策」。这一章给你一套可以照着走的章法,把「拍脑袋」变成「有迹可循」。任何系统,都能用这一套流程拆开。
好消息:做架构判断是有章法的
很多人以为,架构判断是种玄学——靠天赋,靠十年踩坑攒出来的「感觉」。这话对了一半:经验确实重要。但另一半是,顶尖架构师脑子里其实跑着一套相当固定的流程,只是熟练到自己都没意识到。
我们要做的,就是把这套流程拆出来,让你能有意识地、一步步地走。等你走熟了,它也会沉淀成你的「感觉」——但那是建立在章法之上的感觉,而不是凭空的直觉。
这套流程长这样:
┌─────────┐ ┌─────────┐ ┌──────────┐ ┌──────────┐ ┌────────┐ ┌────────┐
│ 需求 │──▶ │ 约束 │──▶ │ 质量属性 │──▶ │ 候选方案 │──▶ │ 取舍 │──▶ │ 决策 │
└─────────┘ └─────────┘ └──────────┘ └──────────┘ └────────┘ └────────┘
系统要做 有哪些不能 系统要「做 有哪几种 每个方案 选一个,
什么? 逾越的边界? 得多好」? 搭法? 各拿什么 并写下
换什么? 为什么
│ │
└──────────────── 业务/规模变化时,回到起点重走一遍 ◀──────────────────────┘注意最下面那条返回的箭头:这不是一次性走完就结束的流程,而是一个会反复重走的循环。 业务变了、规模涨了,约束和质量目标就变了,当初的最优解可能就不再最优——架构因此需要演进(这是第 08 章的主题)。
下面我们逐段拆开。重点会放在第二、三段(约束和质量属性),因为那是新人最容易跳过、却最能拉开差距的地方。
第一步:需求 —— 但要分清两种需求
一切从需求开始。但**「需求」这个词,藏着架构里最重要的一道分界线**,大多数新人从没注意过:
功能性需求:系统要「做什么」。非功能性需求(质量属性):系统要「做得多好」。
这道分界线,值得你刻在脑子里。我们用一个例子把它讲透。
假设需求是:「做一个能上传图片、并分享给别人看的服务」。
功能性需求(做什么)很容易列:
- 用户能上传图片
- 用户能拿到一个链接
- 别人能通过链接看到图片
- 用户能删除自己的图片
这些是「系统得有这些功能」。但请注意:仅凭这些,你根本没法做架构判断。 因为——
「能上传图片」,是给 100 个人用,还是给 10 亿人用? 「别人能看到」,是要求点开秒出,还是转圈三秒也行? 「能分享」,图片要存一辈子,还是七天后自动删? 某个机房着火了,这些图片是可以丢,还是一张都不能少?
这些问题的答案,才真正决定了系统该长什么样。 而它们,全都是质量属性(做得多好):
- 性能:点开图片要在 200 毫秒内显示。
- 可扩展性:要能从 100 用户平滑长到 10 亿用户。
- 可用性:全年宕机不超过几分钟。
- 持久性:图片一旦上传,丢失的概率要极低(比如「十一个九」)。
- 成本:存十亿张图,不能贵到把公司拖垮。
这是架构师最重要的基本功:看到「做什么」,立刻去追问「做得多好」。
功能性需求决定了系统「能不能用」;质量属性决定了系统「该怎么搭」。 同样是「上传图片」,要求秒开 + 永不丢失 + 十亿规模,和要求「能用就行 + 个人小工具」,会导出两套完全不同的架构。
一句话:功能性需求是地基的「用途」,质量属性才是地基的「规格」。 只看用途不看规格,你盖不出对的楼。
为什么新人总跳过质量属性?因为功能性需求是「显性的」——产品经理会写在文档里,白纸黑字。而质量属性是「隐性的」——很少有人主动告诉你「这个要支撑十亿用户、绝不能丢数据」,你得自己去问出来。 这正是下一节「问对问题」要解决的事。
第二步:约束 —— 你不是在真空里做设计
新人常以为,架构是在追求「理论上最好的方案」。但现实是:你永远是在一堆「不能逾越的边界」里做设计。 这些边界,就是约束。
约束和质量属性的区别在于:质量属性是「你想达到的目标」(越好越好),约束是「你绕不开的限制」(就这条件)。 一个是你追求的,一个是给你框死的。
常见的约束有这么几类:
| 约束 | 它会怎么逼你 |
|---|---|
| 团队规模 | 三个人的团队硬上几十个微服务?光运维就把人累垮。架构复杂度不能超过团队的驾驭能力。 |
| 时间 | 「下周必须上线」和「我们有一年」,会逼出完全不同的方案。时间紧,就得选「现在能交付」的,而不是「理论最优」的。 |
| 预算 | 钱决定你能用多少机器、多贵的服务、养多少人。再优雅的方案,烧不起就是空谈。 |
| 合规 / 法规 | 「数据必须存在境内」「医疗数据要满足某某标准」——这类约束是红线,不是「尽量」,是「必须」,违反了方案直接作废。 |
| 已有系统 | 大多数时候你不是从零开始,而是要和一堆「祖传系统」共存。你的设计得迁就它们的接口、它们的脾气。 |
| 第三方依赖 | 你依赖的支付网关、云服务、外部 API,它们的能力上限和故障,就是你的约束。 |
关键认知:约束不是来添堵的,约束是来帮你「砍掉选项」的。
一个没有约束的设计题(「设计一个完美的系统」)其实无从下手,因为选项无穷多。一旦你知道「三个人、三个月、必须合规、要对接老系统」,绝大多数花哨方案当场出局,真正可行的方案就那么几个。 约束越清晰,决策越容易。
所以,新接到一个任务时,先别想方案,先把约束摸清楚。 摸清约束的人,往往比急着画方案的人,最后做得又快又稳。
第三步:质量属性 —— 列一份你的「考量清单」
第一步我们已经明白质量属性有多重要。这一步,给你一份常见质量属性清单,作为你每次思考时的「检查表」——不是每一项都重要,而是逐项过一遍,确保没漏掉那个会要命的。
| 质量属性 | 一句话解释 |
|---|---|
| 性能(Performance) | 系统反应有多快。包括延迟(单次操作多久)和吞吐(单位时间能处理多少)。 |
| 可用性(Availability) | 系统有多大比例的时间是「活着、能用」的。常用「几个九」衡量。 |
| 可靠性 / 持久性(Reliability / Durability) | 数据会不会丢、操作会不会出错。「持久性」特指存进去的数据不会莫名消失。 |
| 可扩展性(Scalability) | 用户/数据涨上来时,系统能不能靠「加机器」从容应对,而不是推倒重来。 |
| 一致性(Consistency) | 多个地方看到的数据是否一致。涉及「刚写的能不能立刻读到」「不同用户看到的是否同一份」。 |
| 安全性(Security) | 能不能挡住攻击、防住越权、保护好敏感数据。 |
| 成本(Cost) | 建设和运营要花多少钱。架构师常常忘了它也是一种「质量」。 |
| 可维护性(Maintainability) | 系统好不好改、好不好懂。新人多久能上手,加个功能要动多少地方。 |
| 可观测性(Observability) | 出了问题,你能不能快速看出「哪里坏了、为什么坏」。 |
| 可演进性(Evolvability) | 业务变化时,架构能不能跟着长大,而不是被锁死。 |
用法很简单:拿到一个系统,把这张表从头到尾过一遍,对每一项问「它对我这个系统重要吗?目标是多少?」
比如做一个「内部报表工具」:性能?中等就行。可用性?挂半小时也能忍。一致性?数据准就行,不要求实时。成本?能省则省。——你会发现大部分项要求都不高,这本身就是重要信息:它告诉你「别过度设计」。
再比如做一个「支付系统」:一致性?钱不能算错,最高优先级。 可靠性?一笔都不能丢。 安全性?红线。 ——同一张表,导出的却是完全不同的侧重。
这份清单,正是每个架构模板里**「质量属性表」**的来源。等会儿你去看 AI 对话产品模板 的第 3 节,会看到它列出了「首字延迟、吞吐、成本、可用性、安全」——那就是把这张通用清单,套到「AI 对话」这个具体场景上的结果。通用框架 + 具体场景 = 那张表。
贯穿始终的核心观点:没有银弹,只有取舍
现在到了整套框架的灵魂。如果这一章你只能记住一句话,记住这句:
没有银弹,只有取舍。任何架构决策,本质都是「用 A 换 B」。
「银弹」是个老说法,意思是「能一击解决所有问题的万能方案」。在架构里,银弹不存在。 每一个让你在某方面变好的选择,几乎都会让你在另一方面变差。
- 想要更快?常常要牺牲成本(加缓存、加机器)或一致性(读到的可能是旧数据)。
- 想要强一致?常常要牺牲性能和可用性(得等所有节点同步好)。
- 想要高可扩展?常常要牺牲简单性(系统变复杂,运维变难)。
- 想要快速上线?常常要牺牲可维护性(欠下技术债,以后还)。
想往这个方向加强 ───▶ 往往要从那个方向割肉
─────────────────────────────────────────
性能 ▲ 成本 ▼ / 一致性 ▼
一致性 ▲ 性能 ▼ / 可用性 ▼
可扩展性 ▲ 简单性 ▼ / 成本 ▼
安全性 ▲ 便利性 ▼ / 性能 ▼
上线速度 ▲ 可维护性 ▼(技术债)这不是说做架构很悲观,恰恰相反:当你接受「凡事皆有代价」,你就从「找最好的方案」(找不到)转向了「找最合适的取舍」(找得到)。 后者才是真正的架构工作。
由此引出一条极其有用的判断标准:
如果有人给你一个方案,说它「哪儿都好,没有任何缺点」——那不是因为方案完美,而是因为他没想清楚。
一个想清楚了的人,一定能告诉你「这个方案好在哪、同时牺牲了什么、为什么这个牺牲值得」。看得到取舍,是想清楚了的标志;看不到取舍,是没想清楚的标志。 你评估别人的方案、或者审视自己的方案时,这一条几乎是万能的试金石。
怎么走完这套框架?关键是「问对问题」
框架是骨架,真正让它转起来的,是提问。前面说过,质量属性和约束大多是「隐性的」,得靠你问出来。所以,会问问题,是架构师的核心手艺。
下面这几个问题,几乎适用于任何系统。拿到一个新需求,先把它们问一遍:
┌────────────────────────────────────────────────────────────┐
│ 架构师的「灵魂六问」 │
├────────────────────────────────────────────────────────────┤
│ 1. 规模多大? 现在多少用户/数据?峰值多少? │
│ 2. 读写比? 是读多写少,还是写多读少? │
│ 3. 一致性要求? 刚写的必须立刻能读到吗?能容忍短暂不一致吗? │
│ 4. 增长预期? 一年后会涨到多少?是平缓还是会爆发? │
│ 5. 失败的代价? 这个东西挂了/数据丢了,后果有多严重? │
│ 6. 有什么约束? 团队多大?多少时间?多少预算?有无合规? │
└────────────────────────────────────────────────────────────┘为什么是这六个?因为它们每一个,都直接锚定一类架构决策:
- 规模和增长,决定你要不要、何时要为「扩展」做准备。
- 读写比,决定你的系统该往「读优化」还是「写优化」倾斜(这会深刻影响数据怎么存,见第 05 章)。
- 一致性要求,决定了那个最经典、最折磨人的取舍:一致性 vs 性能/可用性。
- 失败的代价,决定你要在可靠性、可用性上投入多少——「丢了无所谓」和「丢一条就出大事」是两个世界。
这六问背后,藏着一个新人很难内化、但极其重要的心法:没有「最好的架构」,只有「在这组答案下最合适的架构」。
同样是「聊天功能」,做一个三个人用的内部工具,和做一个十亿人用的微信,答案天差地别——不是因为后者的工程师更厉害,而是因为两者的六问答案完全不同。所以,别一上来就找「正确答案」,先把你的六问答清楚;答案变了,最优解就变了。
走一遍完整流程:设计一个「短链接服务」
讲了这么多,我们拿一个经典又小巧的例子,完整走一遍框架。注意我们的目标不是给出「标准答案」,而是演示「怎么想」。
需求:「做一个短链接服务,把长网址变成 short.ly/x7Kp9 这样的短链,点击后跳转到原网址。」(就是各种「短网址生成器」)
① 需求:先分功能 vs 质量
功能性需求(做什么):
- 输入一个长 URL,生成一个短 URL
- 访问短 URL,跳转到对应的长 URL
- (可能)统计每个短链被点了多少次
就这么三条,简单到几乎没什么可设计的。真正的设计,藏在质量属性里。 于是我们开始问。
② 问对问题(灵魂六问)
- 规模多大? 假设我们对标一个中等服务:每天新建 1000 万条短链。
- 读写比? 关键洞察来了——短链是「生成一次,被点击无数次」的。 一条链接可能被分享后点几百万次。所以读(跳转)远远多于写(生成),读写比可能是 100:1 甚至 1000:1。
- 一致性要求? 「刚生成的短链,要能立刻访问吗?」——最好能,但晚个一两秒也能忍(你刚生成完,通常不会真有人在那一瞬间就去点)。这是个重要的「松一点」的信号。
- 增长预期? 链接只增不减,数据会无限累积。十年下来是个天文数字,得想好怎么存。
- 失败的代价? 「跳转挂了」用户点不开链接,体验差但不致命;「数据丢了」——已经分享出去的短链全部失效,这是灾难,持久性要求高。
- 约束? 假设是个小团队、要尽快上线、预算有限。
③ 从答案里,质量属性自己浮现出来
把六问的答案翻译成质量目标:
| 质量属性 | 目标 | 来自哪个回答 |
|---|---|---|
| 读性能 | 跳转要极快(< 50ms) | 读远多于写,跳转是核心体验 |
| 可扩展性(读) | 要扛住海量读请求 | 读写比 100:1+,峰值在「读」 |
| 持久性 | 短链绝不能丢 | 失败代价:丢了等于已分享的链接全废 |
| 一致性 | 可以「最终一致」 | 晚一两秒能访问到,用户能忍 |
| 成本 | 存储要省 | 数据无限累积 + 预算有限 |
看到了吗? 三条朴素的功能需求,经过「问对问题」,长出了一张清晰的质量目标表。这张表,才是后面所有决策的依据。
④ 候选方案 & 取舍
现在带着这张表,我们看几个关键决策点,每一个都是一次取舍:
决策 A:短码怎么生成?
- 方案一:对长 URL 做哈希,取前几位当短码。简单,但会撞车(不同 URL 哈希到同一个码),得额外处理冲突。
- 方案二:用一个全局递增的计数器,把数字转成更短的字符表示。不会撞车,但需要一个「全局发号」的部件,这本身在高并发下是个挑战。
- 取舍:方案一简单但要处理冲突;方案二干净但引入了「发号器」这个新的复杂点和潜在瓶颈。没有免费的午餐——选哪个,取决于你更怕「处理冲突的麻烦」还是「维护发号器的麻烦」。
决策 B:怎么扛住海量的「读」?
- 我们的读写比是 100:1+,而且热门链接会被反复点。
- 这几乎是在向你喊:加缓存。 把热门短链的映射放进内存缓存,绝大多数跳转请求根本不用碰数据库。
- 取舍:缓存让读变得飞快、还省了数据库压力(对上我们的「读性能」和「成本」目标),代价是多了一层要维护的东西,以及「缓存里是旧数据怎么办」的问题——好在我们前面问出了「能容忍最终一致」,所以这个代价我们承受得起。看,前面问对的问题,在这里直接帮我们拍了板。
决策 C:数据放哪、怎么存?
- 数据形态极其简单:就是「短码 → 长 URL」的键值对应,而且几乎只按短码来查。
- 这种「简单键值、按 key 查、要海量、要快」的形态,天然适合键值型存储,而不是把它硬塞进复杂的关系型结构。
- 取舍:这正是「数据的访问形态决定存储选择」这条通用原则的体现(下一章和第 05 章会反复出现)。
⑤ 决策 & 记下「为什么」
走到这里,你不只得到了一个方案,更重要的是——你能说清每个决策的理由和代价了:
「我们用缓存扛读,因为读写比悬殊且能容忍最终一致;代价是多一层维护和短暂的旧数据,但这个代价我们前面确认过能接受。我们用键值存储,因为数据形态是简单的按 key 查询。我们短码用 X 方案,因为……」
这,就是架构判断。 它和「我随便选了个数据库就开干」的区别,不在于用了什么技术,而在于每一步背后都有「为什么」和「代价」。把这些「为什么」记下来,就是第 08 章要讲的 ADR(架构决策记录)。
📌 真实案例:这套框架不是纸上谈兵
本章用「短链接服务」走了一遍六问。真实世界里的短链(Bitly、TinyURL 等)正是这么设计的:读写比悬殊、重度缓存、KV 存储、唯一 ID 发号。
- 想看这套框架产出的「成品」,直接对照本仓库 短链接服务模板——它的第 3 节(需求与约束)和第 8 节(关键决策)就是本章「六问 + 取舍」走到底的结果。
本章小结
- 做架构判断有章法:需求 → 约束 → 质量属性 → 候选方案 → 取舍 → 决策,而且业务一变,就回到起点重走一遍。
- 架构师最重要的基本功,是分清功能性需求(做什么)和质量属性(做得多好)。 功能决定「能不能用」,质量属性决定「该怎么搭」。前者显性、写在文档里;后者隐性、得自己问出来。
- 约束不是来添堵的,是来帮你砍选项的。 团队、时间、预算、合规、已有系统、第三方依赖——摸清约束,可行方案就剩没几个了。
- 没有银弹,只有取舍。任何决策都是用 A 换 B。 一个「哪儿都好、没有缺点」的方案,不是完美,是没想清楚。看得到取舍 = 想清楚了。
- 会问问题是核心手艺。 灵魂六问:规模、读写比、一致性、增长、失败代价、约束。没有最好的架构,只有在这组答案下最合适的架构。
- 短链接的例子告诉我们:三条朴素的功能需求,经过「问对问题」,能长出一张清晰的质量目标表,而那张表才是一切决策的依据。
这套框架,正好对应每个架构模板里的两个核心小节:「核心需求与约束」(对应本章的需求/约束/质量属性)和**「关键架构决策与权衡」**(对应本章的候选方案/取舍/决策)。
现在就去验证一下: 翻开
../templates/里任意一个模板,直接看它的第 3 节和第 8 节,你会发现它们就是这套框架的实际产物。试着用本章的「灵魂六问」反推:它的设计者当初一定问过这些问题。想清楚之后,你还得把它讲清楚——让团队里每个人都看懂你脑子里的系统。这就需要会画图。
👉 继续阅读:03 · 读懂与画好架构图