系统设计笔记:从零构建可复用的高并发架构知识库
2026/9/15 7:24:44 网站建设 项目流程

很多人看到“system-design-notes”这个项目名,第一反应是:又一份面试突击笔记,存了就等于会了。但我自己整理这份笔记的过程,完全是另一回事——它是我从“会用某个中间件”走向“能设计一套系统”的分水岭。今天不聊面试八股,就聊这份笔记背后,我认为值得每个后端工程师复盘的思路、方法和踩过的坑。

system-design-notes:从零搭建一套可复用的系统设计知识库

我见过太多人把系统设计理解成“画几个框、连几根线”,其实真正的系统设计是用常识和估算撑起来的决策过程。一个功能上线后能不能扛住流量,扩展性好不好,故障恢复快不快,全部取决于你在白板上画下第一笔之前,有没有把问题拆到位。这份笔记的核心价值,就是帮你把那些“只可意会”的经验,沉淀成一套能反复调用的结构化思维。

无论你是在准备架构师面试,还是手头有个新系统要从零搭建,亦或是想搞明白现有系统为什么总在半夜报警,这套笔记的思路都能直接套用。我会把笔记的整理逻辑、核心方法论,以及我在真实业务中反复验证过的实操细节,完整拆开来讲。

1. 系统设计笔记到底在记什么

1.1 好的笔记不是抄答案,而是记录决策过程

我最初整理“system-design-notes”时,犯过一个典型错误:把 GitHub 上各种高星仓库的架构图直接抄进笔记。短链接系统画个 Web 层连 Redis 再连 MySQL,秒杀系统画个队列挡住流量,图是挺漂亮,但关了笔记自己动手设计一个全新业务,依然无从下手。后来我才明白,真正值钱的信息不是那张最终的架构图,而是图中每个节点为什么出现在那里、为什么选这个组件不选另一个、流量和存储是怎么算出来的。

打个比方,这就像学做菜。抄一份菜单只知道“盐 3 克、酱油 10 毫升”,但换一种食材、换一个季节,你就不敢动手了。而如果你记录的是“为什么要放盐、什么时候放盐、酱油和盐的咸度比例是什么”,换什么菜都能调出合适的味道。系统设计笔记也是这样,我后来把每一页都改成了“需求澄清 — 约束条件 — 估算过程 — 方案选型 — 演进路径”五个段落,不把结论放在第一位,而是把思考过程放在第一位。

这样调整之后,笔记才真正变成了可以复用的工具。面试官问任何一个系统,我不会去回忆“标准答案”,而是按这套结构重新推导一遍,推出来的方案天然合理,而且因为是自己推的,细节都经得起追问。做真实项目时也一样,打开笔记越用越厚,每做完一个模块就把新学到的约束条件补进去,笔记就成了个人经验库,而不是别人经验的搬运工。

1.2 为什么强调“反推”而不是“正学”

市面上大部分教程的教学路径是:给你一个系统,拆解它用了什么组件,解释每个组件是什么。我管这叫“正学”,它的问题在于,你学到的是一堆正确答案,但你不知道这些答案是怎么被问题逼出来的。比如你背下来“缓存穿透要用布隆过滤器”,但如果问你:缓存穿透发生的概率有多大?布隆过滤器的误判率调到多少才算可以接受?你答不上来,面试官就知道你是背的,实际做架构也不会做。

所以我的笔记里所有案例都用“反推”的方式记:先摆出明确的问题和约束,再一步一步推导出方案。比如先假设我们要设计一个日活 1000 万的 Feed 流系统,然后问:这个量级下,纯推模式行不行?纯拉模式行不行?二者的瓶颈分别在哪?经过计算得出某个量级下推拉结合是合理的,于是方案自然就出现了。整个过程没有一步是跳跃的,每一步都能拿出来跟人对峙,这才是架构能力。

这种反推的练习做多了,你会发现一个特别重要的副产品:你的技术嗅觉变敏锐了。看到一个系统,你会下意识地估算它的 QPS、存储量、带宽,然后推断它用了什么策略。这份直觉不是天赋,就是反复进行“问题到方案”的推导训练出来的。系统设计笔记,本质上就是这份训练过程的忠实记录。

2. 一套能直接落地的方法论

2.1 需求澄清:先问清楚再动手,至少砍掉一半无效设计

我在笔记第一页就写了加粗的一句话:需求不澄清,方案全是空谈。这是我在真实业务里交过学费才换来的教训。当时我们要做一个用户积分系统,产品经理只给了句“用户签到、做任务、拿积分、换奖品”。我按常规思路设计了积分明细表、流水表、任务表一整套体系,结果上线前一周产品才说:积分要支持逾期清零,而且按自然年滚动清零。这一句话直接让积分账户的存储结构和定时任务逻辑全部重做。

现在我的笔记里,不管哪个案例,第一部分固定是“五个必问的问题”:用户规模有多大,日活和峰值并发分别是多少;数据量级如何,大概要存多少条记录、保留多久;读写比例是多少,是读多写少还是写多读少;可用性要求多高,能否接受分钟级故障;实时性要求多高,数据是必须毫秒级一致还是允许最终一致。这五个问题的答案,决定了后面 80% 的技术选型。

例如“读多写少”和“写多读少”,对应的就是两条完全不同的架构路线。前者重点做缓存、CDN、只读副本;后者重点做异步削峰、消息队列、批量合并写。你不在第一步把这些约束钉死,后面所有讨论都是在踢空气球。我通常还会把一个隐藏问题单独列出来:“这个系统最怕出现什么情况?”是怕数据丢,还是怕超时,还是怕资损——不同业务的核心风险点完全不一样,架构上投入的防守重心也不一样。

2.2 容量估算不是玄学,是小学算术

很多人一听到容量估算就头大,总觉得要懂一堆高深的性能模型。实际上,面试和实践中用到的估算方法,只需要三类基本功:加减乘除、单位换算、常识性的性能参考值。我在笔记里专门做了一页“性能数字速查表”,全是实测或行业公认的数字:单台 MySQL 常规配置下简单查询也就每秒几千 QPS,Redis 单实例每秒能到 10 万级的读操作,千兆网卡的极限带宽约 100 MB/s,单机 Nginx 扛个几万并发连接问题不大。

有了这些参考值,估算就变成了纯粹的算术。举个例子,假设要做一个短链接服务,预估日活用户 100 万,每个用户平均每天产生 2 个短链。那么一天新增短链就是 200 万条,一年下来就是 7.3 亿条。再看写请求的峰值,假设 80% 的请求集中在白天 8 小时,那么平均每秒写入约 69 条;就算峰值是平均值的 5 倍,也就是每秒 350 条左右。这个量级下,你根本不需要分库分表,单库 MySQL 加一个 Redis 缓存完全能扛得住。

读请求的估算同样关键。假设每个短链平均被访问 10 次,那么当天读请求就是 2000 万次,峰值大概每秒 3500 次左右。写 350 QPS、读 3500 QPS,一个标准的三层架构就能吃下:Nginx 做负载均衡,应用服务无状态水平扩展,MySQL 存短链映射关系,Redis 缓存热点短链。你发现没有?整套方案不是拍脑袋拍出来的,而是被估算结果一步一步逼出来的。这个过程写进笔记,比记一百遍架构图都管用。

2.3 高层设计与详细设计:先保证选择题做对,再优化应用题

容量估算做完,方案选型就水到渠成,这属于“选择题”,关键是把方向定对。真正拖垮很多项目的不是选型错误,而是详细设计阶段无限堆细节,忽略了成本和收益的匹配。我一直强调,详细设计要遵循一个原则:能用简单方案解决的,坚决不上复杂组件。比如一个只有几千 QPS 的内部管理系统,完全没有必要上消息队列加异步任务,只要业务逻辑里直接同步调用、加个数据库事务就结束了。

怎么判断是不是“过度设计”呢?我的笔记里有一个“三个问题”的检查清单:这个组件解决的具体问题是什么?不引入它,最坏结果是什么?引入它之后,运维成本和故障面增加多少?如果第三个问题的答案让你犹豫,那就说明这个组件还不到引入的时机。我的经验是,80% 的场景用不上那些“全家桶”式的微服务治理框架——不是框架不好,是业务量级还没有到必须用它的地步,先用简单方案做着,流量起来了再演进,完全来得及。

演进路径也是详细设计里不能省略的部分。很多工程师设计系统时只画了终态架构图,看起来完美,但没人说清楚从第一天怎么起步。我在笔记里每个案例都会补一张“分阶段演进表”:第一阶段单体应用加数据库直接上线,第二阶段引入缓存缓解读压力,第三阶段再引入消息队列和分库分表。这张表让我在设计时能清醒地意识到:每一步演进都要有明确的流量触发条件和回滚预案,架构不是一步到位的艺术品,而是跟业务赛跑的过程中不断长出来的骨架。

3. 经典案例逐个拆:短链、Feed流、秒杀

3.1 短链接系统:一套组合拳打满,适合入门

我一直推荐想入门系统设计的人先做短链接系统,因为它麻雀虽小五脏俱全,几乎覆盖了后半部分所有核心知识点。除了前面估算出的读写量级,短链接还有一个特色问题:如何生成短码。常见方案有三种:哈希后截取、随机字符串、发号器自增 ID。用哈希截取会随着数据量增加而碰撞率上升,需要处理冲突;随机字符串简单但要查重;发号器自增 ID 转 62 进制是最可控的方案。

我笔记里记录了我实际采用的方案:用发号器生成自增 ID,然后转成 62 进制压缩长度。自增 ID 从 10000 开始数(这样短码最短也有 5 位),大概能支撑到 9 亿个短链,对大多数业务绰绰有余。短码生成之后,存储直接用 MySQL,短码做唯一主键,长链接存在一个字段里。写入时有个细节:先查一次长链接是否已存在,如果存在就直接返回旧短码,避免同一个长链接被重复生成无数个短码,导致存储浪费。

读路径上,Redis 缓存是杀招。我的方案是“缓存优先,回源回填”,先用短码查 Redis,命中直接 302 跳转;没命中再查 MySQL,查到后写回 Redis 并设置过期时间,比如 24 小时。为了防止热点短链(比如某个爆款营销链接)把单机缓存打爆,我在 Redis 前面再叠加一层本地缓存(Caffeine)做应用内缓存,TTL 设置 60 秒即可。这套两级缓存的组合,面试时讲出来很有说服力,真实项目里也极其实用。

3.2 Feed 流系统:推拉结合的动态平衡

Feed 流是系统设计里“信息传播模型”的典型案例,每个做过社区类产品的工程师都应该认真拆一遍。它的核心矛盾是:用户关注了很多人,每个人发内容都要扩散给所有粉丝,这个扇出量非常大。假设一个千万粉丝的大 V 发一条内容,纯推模式要往千万个收件箱里各插入一条记录,推送端直接被打爆;而纯拉模式则是每个用户刷新 Feed 时去关注列表里拉取数据,明星大 V 的内容会被上千万人重复读,存储节省了但读压力和后端合并排序压力巨大。

我在笔记里记录的答案是推拉结合,并且给出了明确的阈值:普通用户的内容走推模式,粉丝数小于等于 10 万,直接写入粉丝的收件箱;大 V 用户的内容走拉模式,粉丝数大于 10 万,不写入收件箱,而是在普通用户读 Feed 时,额外并发去拉取大 V 的近期内容,再与收件箱里的内容做 merge 排序。这个 10 万阈值不是拍脑袋定的,而是根据单机每秒能支撑的推送量和平均粉丝数算出来的。

除了扇出策略,Feed 流还有两个配套问题必须处理:一个是 Feed 内容的分页,每页 20 条、按时间倒序,翻页时用游标(cursor)而不是传统 offset,避免深分页时数据库压力暴涨;另一个是内容扩散的延迟容忍度,粉丝读到新 Feed 能接受 1 分钟甚至 5 分钟的延迟,所以推送任务完全可以用异步队列削峰,让界面上的“发布成功”不需要等推送全部完成。这个“最终一致 + 异步化”的思路,在几乎所有内容分发系统里都通用。

3.3 秒杀系统:把流量挡在业务逻辑之外

秒杀系统是系统设计面试里最刺激的题型,几乎把所有高并发难点都暴露出来了。我笔记里把它最核心的一句话提炼为:秒杀不是把系统做得更快,而是把绝大多数流量挡在业务逻辑之外。整个设计的核心目标就一个:让真正参与的请求数量变少,让剩余请求快速返回“已售罄”。

秒杀上线之前先做动静分离:商品详情页、秒杀倒计时这些静态内容全上 CDN,用户点进来时根本不打到源站,这一层就能挡掉 90% 以上的“围观流量”。真正到达应用层的请求,也不能全放进去:用一个本地标记法,在每台应用服务器的内存里维护一个商品剩余库存的近似值,如果本地标记已经卖完,直接返回失败,连 Redis 都不查。只有本地标记还有余量时,才去 Redis 执行 Lua 脚本原子扣减库存,这一步能挡住 99% 的无效流量。

库存扣减之后,还需要把“下单”这个动作异步化。我在笔记里设计的流程是:Redis 扣减成功后,把订单消息丢进消息队列,真正下单的请求由后端 worker 消费执行,数据库层只处理跟库存相等的消息量。这个方案最关键的收益是:数据库永远只接收真实可成交的请求数,而不是面对百万并发拍进来的流量。而为了防止用户重复提交导致超卖,还要用 Redis 记录“已参与用户”,同一用户第二次请求直接拒绝。秒杀系统做完这个设计之后你再回头看,会发现它其实没有多复杂的组件,而是靠每一层都刻意减少流量来实现的,这个“漏斗式”的设计思路本身就是系统设计最大的道。

4. 面试和实战中最容易翻车的五个坑

4.1 背方案不背约束,一问变体就死

我最常看到的情况是,面试者一上来就滔滔不绝讲“我用了 Redis 集群、消息队列、分库分表”,但当我追问“你这个阶段的数据量是多少?为什么这个量级需要分库?不分库会怎样”的时候,他答不上来。归根结底,他没有把方案和约束绑定。所有方案都是相对某个量级和某个场景成立的,脱离约束谈架构,一定是空中楼阁。这个问题的解法我在笔记里反复强调:每一个方案旁边必须标注“适用前提”和“触发阈值”,没有阈值的方案不要写进笔记。

4.2 容量估算拍脑袋,误差超过一个数量级

有些同学算容量时,直接拿日活乘以一个感觉很合理的系数,算出的 QPS 差了两三个数量级。比如把“日活 1000 万”直接当成“每秒并发 1000 万”,这就离谱。正确的方法是要做一层一层的拆解:日活用户数乘以当日人均操作次数,得到当日总请求数;再除以一天的有效秒数(比如白天 10 小时 = 36000 秒),得到平均 QPS;再乘以一个峰值系数(通常取 3~5 倍),得到峰值 QPS。我笔记里专门有一个“估算检查表”,算完之后必须过一遍数量级是否合理。

4.3 过度设计,上来就是微服务全家桶

很多有一定经验的工程师也容易翻这个车:一上来就引入 20 个微服务、每两个服务间加一层消息队列、全部上容器编排。最后系统是设计得非常“高级”,但部署、排障、链路追踪的成本高得吓人,团队根本维护不动。系统设计的第一原则永远是“用最简方案解决当前问题”,微服务的核心收益是独立演进和故障隔离,但如果业务复杂度还没到这个程度,单体加模块化拆分就是最优解。

4.4 忽略故障场景,只画晴天路径

我改同事的设计方案时,最常批注的一句话是:“你这个图只画了正常流程,宕机了怎么办?”一个系统是不是真的设计到位,要看它在故障时是快速失败还是缓慢拖垮全局。缓存雪崩了是直接全量打数据库,还是有限流保护?消息队列积压了是无限 etcetera 追加堆积,还是有降级方案直接关闭非核心功能?这些故障路径必须在设计稿里明确标注出来,宁可图丑一点,也不能缺了这些“不漂亮”的箭头。

4.5 不记录决策,过后完全忘了当初为什么这么选

这是笔记整理层面最容易被人忽视,却最致命的问题。有时候你花了三天时间调研选型,最后定了 A 方案,但三个月后接手的人也好,三个月后的你自己也好,看着这套架构完全不知道为什么不用 B 方案。于是下一次同类问题,又把 B 方案翻出来重新调研一遍,白白浪费时间。我现在写笔记强制自己每页加一个“ADR(架构决策记录)”区块,内容包括:背景、选项、决策、理由、被否方案的致命缺陷。这个区块一写,笔记的价值直接翻倍。

5. 三套可以直接抄走的系统设计工具箱

5.1 我的笔记模板:五段式固定结构

如果你也想建立自己的系统设计笔记,我强烈建议直接套用我迭代了很多版本才定下来的五段式结构:需求澄清、约束条件与容量估算、高层架构设计、详细设计、演进路径与架构决策记录。每一段都固定写在对应的小标题下,不跳过。这样做的最大好处是,笔记积累到一定程度后,不同系统之间可以进行横向对比——同样是 10 万 QPS 的写操作,Feed 流和日志系统分别是怎么处理的?这种对比式思考会反复加深你对方案适用阈值的记忆。

5.2 性能数字速查表:容量估算的起跳点

以下这组数字我实测过多次,可以直接作为起点使用,再根据具体机器配置和业务复杂度做上下调整。要特别说明的是,这些值不是用来炫技的,而是用来快速判断方案是否在一个合理的量级范围的。我通常先按这些参考值做估算,如果算出来的负载离上限还很远,就会毫不犹豫选择简单方案;如果离得很近,则会考虑加缓存、加队列或者横向扩容。

组件参考性能主要瓶颈
MySQL(单机常规配置)简单查询每秒几千 QPS磁盘 IO、连接数
PostgreSQL(单机常规配置)与 MySQL 数量级相当磁盘 IO、锁竞争
Redis(单实例)读每秒 10 万级,写每秒几万级单线程 CPU、网络
Nginx(单机)并发连接 5 万+文件描述符、带宽
Kafka 集群单分区写入每秒几百到几千条磁盘顺序写吞吐
千兆网卡极限吞吐约 100 MB/s带宽上限

使用这张表时,还要时刻提醒自己区分平均值和峰值。系统真正需要面对的永远是峰值流量,所以估算完平均值一定要乘一个峰值系数,并且把这个系数到底取 3 还是取 5 的依据写下来,不要模模糊糊写个“高峰”。我通常会在笔记里记录对应业务的流量曲线,这样峰值系数就有了数据支撑。

5.3 架构自检清单:出方案前过一遍

最后分享一份我在画完架构图之后必过的自检清单,算是这篇笔记的进阶版“抄作业”工具。清单只有八个问题,但每一个都能避免一次重大事故:数据写入是同步还是异步,异步丢失是否可接受;缓存的过期策略是什么,烫点数据有没有被集中过期;单一组件宕机后,流量是否会被转移到替代组件;数据库写入是否会因为单表数据量过大而性能劣化;所有依赖的第三方服务是否都有超时和熔断配置;有没有考虑跨地域部署,网络分区时行为是否可预期;整个链路的可观测性指标是否足够定位故障;以及最后,每个关键决策是否有对应的架构决策记录。这八个问题不是每轮设计都要全中,但每轮都必须过一遍,让这个清单成为肌肉记忆。

我自己的体会是,系统设计笔记整理到第三个月时,最明显的变化不是“会背的方案变多了”,而是“做选择的时候更笃定了”。因为每一个方案背后都有清晰的推导逻辑和明确的量化依据,我不需要靠感觉去拍板。希望这篇文章里沉淀下来的方法论和坑,能帮你少走一些弯路。如果你也开始动笔整理自己的 system-design-notes,记住那句话:别抄答案,记决策过程。这是整份笔记里最值钱的东西。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询