一次没有结论的评审
几年前我参加过一次产品评审。产品经理问了一个很朴素的问题:内容流和下单都在同一个 App 里,为什么不能共用一套服务?
当时在场的后端给出了很多正确答案:
- 内容流读多写少,订单要求强一致;
- 内容可以缓存,库存不能缓存;
- 私信要长连接,下单要短事务;
- 内容允许一两秒延迟,支付回调不能重复。
每个答案单独看都对,但连起来没有回答产品经理真正关心的问题:我现在只有十万用户,哪些能力必须有,哪些可以等?如果明年做到一百万,先改哪一块?如果预算只够招两个人,应该先补哪里?
会议最后变成中间件选型讨论,没人再回到产品阶段。有人主张先上消息队列,有人主张先拆服务,有人主张把所有读请求都加一层缓存。每个主张都能找到支持它的案例,但没有人能说清这些案例对应的是什么规模、什么团队、什么失败代价。
那次之后我意识到,很多架构分歧并不是技术判断不同,而是大家说的“产品”不是同一个阶段的产品。有人按三年后的规模设计,有人按本周要上线的版本设计,双方都能引用正确的最佳实践,却无法形成同一个决策。
更麻烦的是,这种分歧不会在一次会议里结束。它会变成代码里的半成品:一套为未来准备的分片规则,配上今天的单库运维;一个为峰值准备的消息队列,配上还没有监控的消费端;一份写得很完整的 SLO 文档,配上没人看的告警。每一部分都“正确”,合起来却没有人能判断它是否值得。
这本书想补的就是这段缺失的翻译:把产品语言翻译成服务端可计算的约束,再让约束决定能力、边界和成本。它不是一套标准答案,而是一条可以反复使用的推理路径。
三个必须先回答的问题
在讨论任何具体技术之前,本书要求先回答三个问题。它们看起来简单,却能过滤掉大部分无效争论。
第一,这个产品最可能以什么方式坏?
内容流最可能的坏法不是“写入失败”,而是缓存集中失效后数据库被打穿;私信最可能的坏法不是“单条消息发送失败”,而是长连接过载后一群用户同时掉线;下单最可能的坏法不是“接口报错”,而是库存扣了、订单没写、回调又重试。不同的坏法需要不同的能力,而不是同一套“高可用”口号。
第二,为了接住这种坏法,最少需要哪些能力?
“最少”是关键词。一个只有十万 DAU 的内容产品,可能需要缓存、限流和基本监控,但不一定需要多机房、单元化和自研消息队列。提前准备能力不是免费的吗?不是。每一层能力都带来部署复杂度、故障半径、值班负担和招聘要求。能力越多,系统越难被一个小团队真正掌握。
第三,这些能力在当前阶段值得花多少成本?
成本不只是机器钱。它包括研发时间、上线风险、故障排查难度和后续演进阻力。一个团队花三个月搭出来的平台,如果只有两个人在维护,遇到问题时的恢复速度可能不如一个简单的单库加缓存。架构决策如果不算这笔账,就会变成技术债的另一种写法。
这三个问题会贯穿全书。每章结尾的“小结”和“常见错误与边界”,本质上都是在逼读者重新回答它们。
站内已有专题之后留下的空白
这个站点已经有不少相关内容。miniblog 从一个可运行的小产品讲起,覆盖了内容发布、列表、详情和基础后台;design 讨论通用设计原则与取舍;algorithm-interview 处理算法与数据结构题。它们各自解决了一类问题,但读者把它们读完,仍然可能不知道怎么把一个真实产品从“能跑”推到“敢上线”。
缺口不在知识点,而在连续性。
- 知道缓存能提升读性能,不等于知道哪个读路径可以容忍多旧的数据。
- 知道消息队列能削峰,不等于知道哪些动作可以异步、异步失败后用户看到什么。
- 知道灰度发布能降低风险,不等于知道一次数据结构变更应该先双写还是先停写。
- 知道要算容量,不等于知道 DAU、请求量和成本之间哪一条曲线最先失控。
- 知道要写 SLO,不等于知道可用性按请求计、按用户计和按时间计会得到完全不同的结论。
这些“不等于”有一个共同原因:真实产品里,结论从来不是单独成立的。它绑定在具体阶段、具体触发条件和具体失败场景上。脱离这些条件,最佳实践就会变成口号。
站内其他专题也有各自的边界。通用架构书讲的是方法,不负责替某个产品做阶段判断;语言书讲的是语法和标准库,不负责解释为什么这个接口要设计成幂等;运维书讲的是中间件怎么部署,不负责回答这个中间件在这个产品里该不该出现。本书要做的,是把这些相邻知识放回同一条产品时间线上。
所以本书不按中间件组织,也不按设计模式组织,而是按一个互联网产品从起步到规模化的顺序组织。每一章先给产品事实,再给判断,再给失败场景,最后落到可运行的 Go 产物或可复核的计算。
五段连续线
全书的主线可以压成五段:
| 阶段 | 核心问题 | 主要产出 | 对应卷 |
|---|---|---|---|
| 产品约束 | 产品事实如何变成服务端形状? | 形状分类、容量模型、SLO 底线 | 卷一 |
| 基础能力 | 用户是谁、从哪个端来、请求从哪里进? | 账号、资料、BFF、API、入口 | 卷一 |
| 内容社交 | 内容怎么发、怎么流转、怎么被看见? | 内容状态机、Feed、关系、IM、通知 | 卷二 |
| 交易增长 | 钱和权益怎么不出错? | 库存、订单、支付、券、实验 | 卷三 |
| 规模化 | 什么时候拆、怎么拆、拆完怎么退? | 单元化、分片、平台化、成本治理 | 卷四 |
这个顺序不是为了把内容平均分成四份,而是因为后一段的问题必须在前一段的约束下才有意义。没有账号和入口,内容社交只能停留在单机演示;没有内容与交易的真实流量,规模化讨论就只能停留在拓扑图上。
卷一之所以从产品约束开始,而不是从账号表结构开始,是因为账号模型本身也依赖产品事实。一个只有 App 登录的产品和一个同时支持 App、Web、小程序、第三方授权的产品,会话模型、设备模型、注销流程完全不同。先写表,再补产品差异,通常会在第三端接入时推倒重来。
为什么不是按技术分层写
按“接入层、业务层、存储层”组织,看起来更整齐,但会掩盖最关键的信息:同一层里的两个模块,可能因为产品事实不同而需要完全不同的失败策略。
例如网关。内容流的网关主要处理缓存回源和限流,私信的网关主要处理长连接、心跳和广播,下单的网关主要处理认证、幂等键和重放保护。它们都叫“网关”,但需要的连接模型、超时策略和降级方式并不相同。只按层讲,读者会得到一张漂亮的架构图,却不知道每一层内部为什么要分叉。
按产品阶段组织,则允许同一个技术名词在不同章节承担不同责任。读者能看到“缓存”在起步期是省数据库连接的手段,在增长期变成一致性问题,在规模期又变成成本和热点的来源。这种变化比一张静态分层图更接近真实工作。
每一段都留下可检查的产物
五段主线不是五个故事,而是五组可以检查的产物。卷一留下形状分类器、容量模型和 SLO 计算;卷二留下内容状态机、Feed 与 IM 的参数表;卷三留下订单与支付的状态机、对账清单;卷四留下拆分触发条件、演练模板和架构健康度自评。
这些产物不一定都能直接用于生产,但它们必须能被复核。一个分类器要能跑测试,一个容量模型要能代入假设数字,一份 ADR 要能说出备选方案和回退条件。只写结论、不留下检查方式的章节,在本书里是不合格的。
这本书不做什么
明确边界比罗列内容更重要。以下五件事,本书刻意不做:
第一,不重复《后端架构设计》的方法论综述。那套书讲通用架构模式、质量属性与演进方法,覆盖面更广;本书只处理互联网产品特有的那条链路:产品形态如何改变读写路径、数据模型与容量结构。遇到通用的限流、缓存、分布式事务机制,正文只给判断和取舍,细节用站内链接指回已有文章。
第二,不做中间件安装手册。Redis、Kafka、PostgreSQL 的部署参数、集群运维和故障排查属于另一类书稿。本书会说明为什么需要某一层能力、它应该放在链路的哪个位置、失败时用户会看到什么,但不会给出可以直接复制的生产配置。
第三,不承诺“照着做就能支撑千万 DAU”。书里的数字除明确标注运行输出外,都是案例假设值,用来演示推导过程。真实系统的容量取决于请求体大小、缓存命中率、数据分布、团队运维能力和预算,任何一个都可能让结论翻转。
第四,不用成功案例替代失败分析。本书更愿意花篇幅讲形状错配、缓存击穿、异步丢消息、灰度回滚失败这些不体面的场景,因为架构判断的价值往往在出错时才显现。只讲成功路径的书,读起来很顺,用起来很容易漏掉边界。
第五,不替读者做组织和商业决策。团队怎么分工、预算怎么批、产品要不要做某个功能,这些问题的答案取决于公司上下文。本书只会指出:某些技术选择会反过来约束组织,例如单元化会要求明确的用户路由归属,平台化会要求有人长期维护内部契约。知道这层关系,比拿到一个“标准组织架构”更有用。
为什么只围绕「回声」写
书里反复出现一个叫「回声」的假想产品。它有内容流、私信、个人主页、站内下单和一套最基础的运营后台。它不是一个真实公司的产品,也不是若干案例拼凑出来的“平均产品”,而是一个刻意保持一致的实验对象。
围绕一个产品写有三个好处。
第一,约束可以累积。第 1 章定下的读写比和 SLO,会在第 8 章的缓存决策和第 12 章的容量模型里继续使用;第 3 章的会话模型,会在第 5 章的 BFF 和第 13 章的端到端用例里再次出现。读者能看到同一个假设如何影响后面的结论,而不是每章换一个干净的例子。
第二,取舍会互相碰撞。内容流希望缓存久一点,个人主页希望资料更新立刻可见,订单希望库存绝对准确。真实架构的难点不是分别满足这些要求,而是在同一个系统里给它们划出不同的路径和承诺。单一产品的连续性让这些碰撞无法被回避。
第三,失败可以追责到具体决定。某次缓存集中失效导致数据库被打穿,读者可以回到第 8 章看当时的缓存窗口是怎么定的;某次灰度回滚不干净,可以回到第 10 章看双写窗口和开关边界。案例之间不是独立故事,而是同一套决策的后果。
「回声」也会分阶段成长:起步期按十万 DAU 假设,增长期按一百万,规模期按一千万。每章会说明结论适用于哪个阶段。把一个千万级方案搬进只有十万用户的系统,和把十万级方案硬撑到一千万,都是本书要避免的错误。
「回声」不是什么
它不是一套可以直接部署的开源项目,也不是某个真实产品的匿名化版本。它的业务规则被刻意简化,只保留会影响服务端形状的部分:内容有作者、可见性和审核状态;私信有会话、序号和离线补拉;订单有库存、支付回调和履约状态。至于推荐算法、广告竞价、复杂权限树,本书只划边界,不展开。
它也不是一个“最佳实践示范”。书里会展示「回声」做错的决定、补丁式的修复和后来被推翻的方案。一个只展示正确答案的案例,会让读者误以为架构是一次性设计出来的;真实情况通常是先做一个能用的版本,再在故障和增长中逐步修正。
三种读法
不同读者不需要用同一种方式读这本书。
| 读法 | 适合谁 | 怎么读 | 读完得到什么 |
|---|---|---|---|
| 按卷通读 | 第一次系统接触服务端架构的读者 | 从卷一第 1 章顺序读到卷四,每章至少跑一次代码 | 一条完整的推理链,以及一套可复用的判断顺序 |
| 按问题跳读 | 正在做具体项目或架构评审的读者 | 先看目录里的症状对照表,再跳到对应章节,最后回到第 1、12、13 章补约束 | 针对当前问题的决策依据与失败清单 |
| 只跑代码 | 有后端经验、想快速验证结论的读者 | 从附录 B 进入 webapp-lab,按包运行测试,再回读对应章节 | 可复现的实验结果,以及对代码边界的直觉 |
按卷通读最容易建立整体感,但不必强求一次读完四卷。卷一的许多结论在卷二、卷三会被重新使用,如果时间有限,至少把第 1、2、13 章连起来读一遍,知道一条产品约束如何走到可运行基线。
按问题跳读要防止一个误区:只读结论,不看前提。每章开头的产品事实和假设数字不是装饰,它们决定了后面的建议是否适用于你的场景。跳读时至少把该章的“失败场景”和“常见错误与边界”看完。
只跑代码的读者请注意,代码是论证的一部分,不是全部。测试通过只能说明某个纯函数在给定输入下行为正确,不能说明你的生产系统已经具备同样的能力。代码之后的解释、边界和失败场景仍然要读。
不建议的读法
有三种读法效果通常不好。
第一种是只背结论。例如记住“读多写少要加缓存”,却不记缓存一致性窗口取决于产品能容忍多旧的数据。换一个产品,结论可能正好相反。
第二种是跳过失败场景。很多人读架构书只看最终方案,不看方案是在什么故障之后被采纳的。这样得到的方案缺少触发条件,遇到相似但不同的问题时容易照搬。
第三种是把代码当成唯一证据。代码能证明某个判断在测试输入下成立,不能证明它在真实流量、真实数据分布和真实运维条件下成立。书中的代码分级就是为了明确这一点:L1 通过不等于生产可用。
读者画像与前置知识
这本书主要写给三类人:
- 从产品、运营或前端转做服务端,第一次负责一个完整产品域的工程师;
- 有后端经验,但过去的系统由别人做架构决策,现在需要自己判断边界与成本的工程师;
- 需要评审架构方案的技术负责人、产品负责人,以及准备系统设计面试的读者。
前置知识不多,但也不能完全空白。读者最好写过 Go 或类似语言,理解 HTTP 请求与响应、关系型数据库的基本事务、缓存的基本概念。不要求读过分布式系统论文,也不要求有大规模运维经验;遇到超出范围的概念,正文会给出直觉解释和站内延伸阅读。
如果你完全没写过服务端代码,建议先完成一个最小 Web 服务再回来。本书不会从变量和循环讲起,代码块默认读者能看懂结构体、接口和表驱动测试。
谁可能读不下去
如果你期待的是“十步搭好千万级架构”的清单,这本书会让你失望。它不提供跨过阶段判断的捷径,也不会把复杂取舍压缩成一句口号。
如果你只关心某个框架的用法,也应该先去读对应的框架文档或语言书稿。本书的代码是为了验证判断,不是为了展示框架特性。
如果你所在团队还没有稳定的产品和流量,卷三、卷四的很多问题会显得遥远。这很正常,可以先读卷一和卷二,把基础能力与内容链路的边界建立起来,等业务真的走到那一步再回来。
写作与验证方式
本书对事实的处理有一条硬规则:只有本机真实运行过的命令和输出,才会写成“运行输出”;没有跑过的数字,一律写成“案例假设值”或“预期结果”。
这条规则看起来啰嗦,但它决定了读者能否信任书里的结论。一个编造的“实测 QPS”比一个诚实的假设值危险得多,因为读者会以为它可以复用。案例假设值至少提醒读者:这是推导用的输入,不是生产承诺。
代码同样如此。每段代码都来自配套工程 webapp-lab,代码块头部标出文件路径、验证级别和测试命令。读者可以逐字节对照,也可以只跑某一个包。代码分级在附录 B 有完整说明,但先记住一句话:本书卷一只做到 L1,端到端用例在 L2,真实依赖和故障注入不会伪装成本地测试。
三个写作立场
第一个立场是产品优先。技术选型必须能回到产品事实,否则再流行也不采用。书里会反复问:这个能力解决的是哪个用户场景?如果没有它,用户会看到什么?
第二个立场是失败优先。每章至少有一个失败场景,而且尽量写成有后果的具体过程,而不是“可能导致不可用”这种空话。失败场景不是为了吓人,而是为了让读者知道能力的边界在哪里。
第三个立场是可复现。结论要么能通过代码验证,要么能通过计算复核,要么能通过明确标注的假设推演。三者都没有的结论,不应该出现在书里。
这三个立场会限制写作范围,也会让一些话题显得不够全面。但比起给出一套看似完整、实际无法验证的架构大全,我更愿意把有限的范围写清楚。
回声的第一版:一个能跑的起点
为了不让读者误以为书里的系统一开始就是最终形态,这里先交代「回声」的第一版。它假设十万 DAU,团队三到五人,预算有限,目标是尽快验证产品,而不是提前搭建平台。
第一版的技术选择很朴素:
| 决策 | 第一版做法 | 当时接受的风险 |
|---|---|---|
| 服务拆分 | 一个 Go 服务,按包分模块 | 单进程故障会同时影响内容、私信和下单 |
| 数据存储 | 一个 PostgreSQL 实例 | 单库容量和连接数都有上限 |
| 缓存 | 一个 Redis,缓存内容列表和热门详情 | 缓存集中失效会打穿数据库 |
| 异步 | 进程内任务加一张待处理表 | 进程重启可能丢任务 |
| 发布 | 单机滚动替换,手工回滚 | 回滚期间可能短暂不可用 |
| 观测 | 基础日志、少量指标和人工告警 | 故障发现依赖用户投诉 |
这些选择不是“最佳实践”,而是在当前阶段最容易被团队理解和维护的方案。它们有意接受了一些风险,因为团队还没有足够的流量和人力去维护更复杂的系统。
第一版也会做出几个后来被推翻的决定。比如内容列表最初直接查数据库,因为数据量小、查询简单;当读写比上升后,才加缓存和读模型。私信最初用轮询,因为实现快;当在线用户增加后,才改成长连接。下单最初和内容共用数据库,因为事务简单;当库存和支付回调变复杂后,才划出独立边界。
读者在后续章节看到这些改动时,应该关注三个问题:触发条件是什么?改动的代价是什么?如果改错了,怎么退回去?如果只记住“后来用了缓存/长连接/独立库”,而不记触发条件和回退方案,就会把演进结果误当成起点。
第一版的价值,是给全书一个诚实的参照。没有它,后面的方案看起来像凭空出现;有了它,读者能看到每个能力是在什么压力下被引入的,以及它又带来了什么新问题。
从故障反推:本书如何使用案例
本书的很多章节从一次故障或一个争议开始,而不是从一个定义开始。这不是为了制造戏剧性,而是因为架构判断的触发条件通常藏在故障里。
比如一个增长期的内容产品,平时数据库 CPU 只有三成。某次运营活动把首页推荐位换成一条爆款内容,缓存同时过期,所有实例一起回源。假设回源请求在十秒内从每秒几百涨到每秒几千,数据库连接池先耗尽,接着接口超时,客户端重试又把流量放大一轮。事后团队加机器、延长缓存时间、增加本地缓存,但真正的问题不是缓存时间太短,而是没有给回源设并发上限和降级路径。
这个案例在书里会被拆成三个问题:读路径能不能容忍旧数据?缓存失效时谁来保护数据库?用户看到的是空白、旧内容还是错误页?三个问题分别对应第 8 章的缓存决策、第 7 章的回源保护和第 11 章的 SLI 设计。读者不需要记住事故细节,只需要记住这三个问题。
再比如一次发布事故。团队要给用户表加一个字段,采用双写:新代码同时写旧字段和新字段,读路径还读旧字段。灰度到一半发现新字段写入失败率偏高,团队决定回滚。回滚后旧代码不认识新字段,但新代码已经写了一部分数据,导致同一批用户在不同实例上看到不同的资料。问题不在双写本身,而在回滚方案没有定义“已经写入的新数据怎么办”。
这类案例在本书里不会给出“正确做法”四个字就结束,而会追问:双写窗口多长?读路径什么时候切换?回滚时新数据保留还是清理?清理失败怎么补偿?这些追问才是第 10 章真正要交付的东西。
需要说明的是,书里的故障场景也是案例假设,不是对某家公司的影射。它们的价值在于展示决策链,而不是提供可对号入座的事故报告。读者应该把注意力放在“如果这件事发生在我这里,我能不能发现、能不能止损、能不能回退”上。
关于假设数字的阅读建议
书里会出现大量数字:DAU、请求数、峰值系数、延迟、命中率、副本数、成本。除了明确标注运行输出的部分,它们都是案例假设值。读取这些数字时,建议先问三个问题。
第一,这个数字来自产品指标、压测,还是作者假设?
产品指标回答“用户实际做了什么”,压测回答“系统在受控条件下能做到什么”,作者假设只回答“为了让推导继续下去,先取这个值”。三者不能混用。把假设值写进容量规划,和把压测峰值当成日常均值,都会导致错误结论。
第二,它对应的窗口和口径是什么?
“日活一百万”可能指打开过 App 的去重设备,也可能指登录过的账号,还可能指产生过一次有效行为的用户。三个口径可能相差几倍。“峰值 QPS 五千”可能指一秒内的瞬时峰值,也可能指五分钟平均值。口径不同,需要的容量余量完全不同。
第三,如果它错一倍,结论会不会翻转?
这是最有用的一问。如果请求数错一倍,副本数从十五变成三十,结论只是成本上升;如果可用性目标从三个九提到四个九,错误预算会缩小十倍,整个发布流程和故障响应方式都要改变。前者是量变,后者是质变。读者应该优先关注那些会让结论翻转的假设。
书里不会假装这些数字是精确的。相反,很多章节会故意给出区间,让读者看到上限和下限之间的差距。容量评估用区间而不是单点,就是为了让假设误差显式传播,而不是藏在一个看起来精确的数字里。
这本书的限度
任何一本书都有它看不到的地方,提前说清楚比读完再失望好。
第一,它不能替代真实生产经验。书里的失败场景和测试结果都是受控环境下的推演。真实系统里还有网络抖动、硬件故障、供应商变更、流量作弊和人为误操作,这些只能在实际值班和复盘中慢慢建立直觉。
第二,它假设产品有典型的客户端与服务端结构。以 App、Web 或小程序为入口,服务端承担账号、内容、交易和通知。对于嵌入式、纯离线工具、强端侧计算或物联网场景,很多章节只能提供类比,不能直接套用。
第三,它不讨论组织政治和商业博弈。一个技术上合理的方案,可能因为团队边界、预算归属或考核目标而无法落地。本书会指出技术选择对组织的要求,但不会教读者如何在公司里推动决策。
第四,它带有作者的经验偏差。书里反复强调的“阶段判断”“失败场景”“可运行产物”,是作者认为最重要的部分,不代表它们是唯一正确的关注点。读者应该用自己的产品和团队去校准,而不是把书里的优先级当成普适标准。
第五,它会过时。Go 版本、云产品、中间件能力都在变化,书里的命令和代码只能保证在写作时的配套工程里可运行。读者读到较晚的版本时,应先用附录 B 的方法重新验证,再判断结论是否仍然成立。
承认这些限度,不会削弱书的价值,反而能让读者更准确地使用它。把一本书当成地图,而不是当成领土,是比较安全的态度。
一个可执行的阅读节奏
如果你打算按卷通读,可以按四周安排卷一:
| 周次 | 章节 | 重点 | 建议投入 |
|---|---|---|---|
| 第一周 | 第 1–2 章 | 产品形状、容量、SLO、用例与 ADR | 6–8 小时 |
| 第二周 | 第 3–7 章 | 账号、资料、BFF、API、入口 | 8–10 小时 |
| 第三周 | 第 8–11 章 | 缓存、异步、发布、可观测性 | 8–10 小时 |
| 第四周 | 第 12–13 章 | 容量成本、端到端收口 | 6–8 小时 |
这个安排只是参考。每章正文通常需要一到两小时,跑代码和改假设再加半小时到一小时。如果某一章与你的当前项目无关,可以只读小结和常见错误,把时间留给更需要的章节。
不建议一次读太多章。架构判断需要时间沉淀,连续读五章而不动手,通常会变成“看过”而不是“会用”。每读完一章,至少做一次假设替换或代码运行,效果比多读一章更好。
如果只有十小时,建议读第 1、2、13 章,再挑一个与你工作最相关的章节。这样至少能看到一条从产品约束到端到端基线的完整链路,而不是零散的知识点。
阅读时可以做一张简单的记录表,只写三列:这一章的假设、结论、失败场景。读完一卷后回看,你会发现很多结论其实依赖同一组假设,也会更容易发现哪些章节需要重读。这个动作不需要工具,一张纸或一个文本文件就够。
小结
这本书的起点不是“如何设计一个高并发系统”,而是“如何判断当前产品需要什么样的服务端,以及为此愿意付出什么代价”。它用「回声」保持约束连续,用五段主线连接产品与规模化,用可运行代码把关键判断固定下来,同时明确不覆盖中间件运维、算法推导和真实多机房部署。
如果你读完后能对一个新的产品说出下面三句话,序言的目的就达到了:这个产品最可能以什么方式坏;为了接住它,最少需要哪些能力;这些能力在当前阶段值得花多少成本。
序言只回答“为什么读”。接下来前言会回答“怎么读”:四卷如何分工、代码如何组织、L1 到 L4 分别意味着什么、遇到同名指标时先看哪个口径。如果你已经决定继续,可以直接翻到前言;如果你还在犹豫这本书是否适合当前项目,建议先读第 1 章的三个产品事实,再决定要不要投入时间。
无论从哪一页开始,都建议保留一个习惯:每读完一个结论,写下它依赖的假设和可能的失败方式。这个动作比记住任何架构图都更有用,因为它会在你真正做决策时提醒你:结论不是免费的,它需要条件。
常见错误与边界
最后提醒一句:序言里的所有判断都不是让读者照搬,而是让读者在遇到分歧时多问一层。
如果一本书能让你在评审会上少说一句“最佳实践就是这样”,多问一句“我们的假设是什么”,它就已经发挥了作用。
- 把本书当成架构模板。书里的分类、阈值和代码都是论证工具,不是可以直接套用的生产方案。
- 把案例假设值当成实测数据。DAU、QPS、延迟和成本除运行输出外均为假设,错一倍就可能改变结论。
- 跳过产品阶段直接看技术方案。同一个“缓存”在起步期和规模期承担的责任完全不同。
- 只读成功路径。真正决定系统能否上线的,往往是失败时用户看到什么、服务端还能不能恢复。
- 把代码通过当成架构正确。L1 测试验证的是局部逻辑,不能替代端到端、压测和真实故障演练。
- 用一本书解决所有问题。通用架构、中间件运维、算法与组织问题,需要配合站内其他专题一起读。
- 追求一次设计到位。更现实的做法是给每次演进设定触发条件、回退方案和可验证的结果。
- 忽略团队承受能力。一个理论上更优雅的方案,如果没人能维护,长期表现通常不如一个朴素但可解释的方案。
读一本书最有价值的时刻,往往不是它替你做了决定,而是它让你发现一个原本没问出口的问题。
如果序言只能留下一个提醒,那就是:先把产品事实写清楚,再让架构回答问题。
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。