
1. 这不是笔记是系统设计能力的显微镜“system-design-notes”这个标题乍看平平无奇像极了GitHub上成千上万份被star过又沉底的仓库名。但如果你正站在准备System Design Interview的路口——无论是刚刷完200道LeetCode、手写过三遍LRU缓存、却在面试官问出“如果Twitter要支持每秒50万条推文你会怎么设计”时突然失语或是已经工作三年、能独立交付模块、却在参与架构评审时听不懂“服务分层”“读写分离”“一致性哈希”这些词背后的取舍逻辑——那这份notes就不是随手记下的碎片而是一面显微镜它把抽象的“系统设计”四个字拆解成可触摸、可验证、可复盘的肌肉记忆。我见过太多人把System Design当成玄学。有人死记硬背“CAP定理三选二”却说不清为什么ZooKeeper选CP而Eureka选AP有人熟练画出微服务架构图但当面试官追问“服务间调用失败率突然从0.1%飙升到5%你第一步查什么”立刻卡壳还有人花三个月啃完《Designing Data-Intensive Applications》合上书却连一个简单的短链生成系统都画不出核心组件间的流量走向。问题不在努力而在输入和输出之间缺了一座桥——这座桥不是理论堆砌而是把每个设计决策背后的真实约束、权衡代价、落地陷阱用最朴素的语言钉在具体场景里。这份notes的全部价值就藏在“notes”这个词的本义中它不是教科书不是PPT而是我在真实项目里踩坑后、在模拟面试中被拷问后、在深夜复盘线上故障后一笔一划写下的“当时为什么这么选”“后来发现哪里错了”“下次一定先验证什么”。比如为什么在日志聚合系统里Kafka的分区数不能简单设为CPU核数的两倍为什么用Redis做分布式锁时SETNX加EXPIRE的组合在高并发下会失效这些答案从来不在官方文档的“最佳实践”章节里而在你亲手部署、压测、观察监控指标的过程中。所以当你打开这份notes别把它当知识库去检索而要当成一份带注释的手术记录——每一条笔记都对应着一次真实的系统切口、一次血淋淋的权衡、一次事后诸葛亮式的清醒。2. 从“画图”到“决策”系统设计的本质是约束求解很多人误以为系统设计面试就是考画图能力画个方框代表用户箭头连到API Gateway再连到一堆Service最后接个Database——图很完整但离合格还差十万八千里。真正的系统设计本质是一场在多重硬性约束下的动态求解过程。它不追求“完美架构”只追求“在当前约束下最不坏的选择”。而这份notes的核心骨架正是围绕四类不可妥协的硬约束展开规模Scale、可靠性Reliability、延迟Latency、成本Cost。这四个字母构成了所有设计决策的坐标系原点。2.1 规模不是“大”而是“增长路径”的具象化“支持千万级用户”这种描述毫无意义。真正关键的是用户量、请求量、数据量的增长曲线是什么峰值出现在什么时间增长是线性的、指数的还是脉冲式的我在做电商秒杀系统时曾天真地按日常QPS的10倍预估峰值结果活动开始3秒内订单创建接口的TPS就突破了预估上限的3倍——因为用户行为不是均匀分布而是集中在开抢瞬间的毫秒级脉冲。这份notes里所有关于“水平扩展”的讨论都始于对增长模式的量化拆解。比如计算数据库分片数绝不是拍脑袋定8个或16个而是基于三个数字单实例最大连接数如MySQL默认151、单实例安全QPS上限实测值非理论值、预估峰值QPS。公式很简单分片数 ceil(预估峰值QPS / 单实例安全QPS)。但难点在于获取“单实例安全QPS”——这必须通过真实压测得出且要覆盖慢查询、连接池耗尽、磁盘IO瓶颈等不同维度。我吃过亏第一次压测只关注了CPU和内存上线后发现高峰期大量请求因磁盘IO等待超时原因竟是日志写入和业务查询争抢同一块SSD。所以notes里明确标注“压测必须包含混合负载至少包含70%读20%写10%日志写入”。2.2 可靠性99.9%不是目标而是成本与体验的平衡点“三个9”99.9%可用性意味着每年允许宕机约8.76小时。但这个数字背后是无数个具体决策是否引入异地多活是否为每个核心服务配置熔断降级是否对所有外部依赖做超时和重试这些选择没有标准答案只有成本核算。例如为支付服务实现同城双活需要双倍的服务器、数据库、网络带宽以及复杂的流量调度和数据同步机制。但若支付服务宕机1小时公司损失可能远超一年的双活建设成本。而对一个内部运营报表系统99.5%的可用性可能已足够——因为它的用户可以接受“今天报表晚点出来”。这份notes的价值在于把每个可靠性方案的成本具象化。比如“引入消息队列解耦”这一常见建议notes里会写明Kafka集群的运维复杂度提升30%消息积压排查时间增加50%但能将下游服务故障导致上游超时的概率从100%降至0.1%。这种量化对比才是决策依据。我见过最典型的错误是把“用了Kafka”等同于“高可靠”却忽略了Kafka本身也是单点故障源——如果Kafka集群挂了整个异步链路就瘫痪了。所以notes里专门有一节叫“Kafka的可靠性补丁”列出必须做的三件事1设置min.insync.replicas2并确保replication.factor32消费者组启用enable.auto.commitfalse手动控制offset提交时机3为Kafka集群配置独立的监控告警而非仅依赖应用层埋点。2.3 延迟毫秒级的战争发生在每一跳网络与每一次磁盘寻道之间用户感知的“慢”往往不是某个环节的绝对延迟而是多个微小延迟的叠加。一个典型的Web请求链路DNS解析20-100ms→ TCP三次握手10-50ms→ TLS握手50-200ms→ HTTP请求发送1-5ms→ 服务端处理10-100ms→ 数据库查询5-50ms→ 网络传输返回10-50ms。即使每个环节都“很快”总延迟也可能轻松突破300ms——而研究表明用户等待超过250ms就会产生明显挫败感。这份notes里所有关于缓存、CDN、连接池的讨论都紧扣“如何砍掉哪一跳”。比如为什么Redis缓存要设置TTL表面看是防止数据过期深层原因是避免缓存雪崩——当大量key在同一时刻过期请求会瞬间打穿缓存直击DB。但更隐蔽的问题是TTL设置过长会导致缓存与DB数据不一致的时间窗口变大设置过短又会频繁触发缓存穿透。notes给出的实操解法是“双TTL策略”主缓存如商品详情用较长TTL如2小时同时维护一个短TTL的“探针key”如item:123:staleTTL5分钟每次读取主缓存前先检查探针key是否存在若不存在则异步刷新主缓存并重置探针key。这个方案把一致性窗口从2小时压缩到5分钟且完全规避了雪崩风险。它不是教科书里的标准答案而是我在一个实时价格系统里为解决“价格更新后用户看到旧价长达2小时”的投诉熬了两个通宵调试出来的。2.4 成本钱不是万能的但没钱是万万不能的技术人常陷入“技术洁癖”认为只要方案最优成本自然合理。现实恰恰相反成本往往是第一约束。我参与过一个视频转码服务的设计团队最初方案是自建GPU集群理由是“完全可控、性能最优”。但财务同事拉出一张表一台A100 GPU服务器月租3.2万元按峰值需求需12台年成本近460万而使用云厂商的Serverless转码服务按实际转码时长计费预估年成本仅80万且无需运维GPU驱动和CUDA版本兼容问题。最终我们选择了后者并把省下的380万投入到提升转码算法效率上——这才是成本驱动的技术优化。这份notes里所有架构图都附带一张“成本影响矩阵表”横向是方案选项如自建Redis vs 云Redis纵向是成本维度硬件采购、带宽费用、人力运维、故障恢复时间。例如对比“数据库读写分离”和“数据库分库分表”前者初期成本低只需加一台从库但扩展性有限从库数量受主库复制压力限制后者初期成本高需改造分片逻辑、引入Sharding中间件但长期扩展性好。notes的结论不是“选哪个”而是“当你的读QPS超过5000且持续增长时读写分离的边际收益开始递减此时应启动分库分表评估”。这种基于数据阈值的决策点比任何主观判断都可靠。3. 从“概念”到“代码”把设计决策翻译成可执行的验证清单系统设计最容易被忽略的环节是“设计完成之后做什么”。很多人的笔记停在画完架构图就结束了仿佛图一画系统就自动跑起来了。但现实是每一个方框、每一条连线背后都藏着数十个需要验证的细节。这份notes最硬核的部分就是把每个设计决策翻译成一份可逐项打钩的“验证清单”。它不告诉你“应该怎么做”而是逼你回答“你确认做到了吗”。3.1 API网关层不只是路由更是流量的守门人API网关常被简化为“统一入口”但它的核心价值是流量治理。这份notes里针对API网关的验证清单包含12项其中7项直接关联线上稳定性。例如“限流策略是否区分用户级别”——这是血泪教训。我们曾为登录接口设置全局QPS限流1000结果一个恶意脚本用100个账号轮询瞬间打满限流阈值导致所有正常用户无法登录。正确做法是对登录接口实施“用户ID维度限流”如单用户每分钟最多5次再叠加“IP维度限流”如单IP每分钟最多100次。notes里给出了NginxLua的实现片段# 基于用户ID的限流需从JWT解析user_id limit_req zoneuser_limit burst5 nodelay; # 基于IP的限流 limit_req zoneip_limit burst100 nodelay;另一个关键项是“超时时间是否分级设置”。很多团队给所有后端服务设置统一超时如3s但这是灾难。支付回调必须严格保证最终一致性超时应设为30s以上而搜索建议接口200ms无响应就该返回空建议。notes要求每个上游服务的超时时间必须在网关配置中显式声明并与该服务的P99延迟对齐。我们曾因未分级超时导致一个P99800ms的推荐服务拖垮了整个首页因为网关等它3s才放弃。3.2 数据库层ACID不是银弹隔离级别是把双刃剑数据库设计笔记里最常被误解的是事务隔离级别。很多人死记“READ COMMITTED防止脏读”却不知道在高并发下它可能导致“不可重复读”进而引发业务逻辑错乱。例如库存扣减场景事务A读取商品库存为100事务B在此期间扣减1件并提交事务A再次读取时库存变为99——如果A的业务逻辑是“库存50才发优惠券”两次读取结果不同就会导致本不该发券的用户收到券。这份notes的验证清单强制要求每个涉及资金、库存、状态变更的核心事务必须明确标注其隔离级别并通过SQL注入测试验证效果。测试方法很简单开启两个MySQL客户端一个执行SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;另一个执行SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;然后在相同数据上执行读-改-读操作观察结果差异。notes还特别提醒“不要盲目升级到SERIALIZABLE它会极大降低并发性能。优先考虑应用层加锁或乐观锁version字段”。3.3 缓存层穿透、雪崩、击穿不是名词是待解决的故障单缓存相关笔记我花了最多篇幅写“如何证明你的缓存方案真的有效”。验证清单第一条就是“缓存命中率是否达到预期”。很多人只看Redis的keyspace_hits指标却忽略了应用层缓存如Caffeine的命中率。我们曾遇到一个诡异问题Redis命中率95%但整体接口P95延迟反而升高了——排查发现应用层本地缓存因GC频繁被清空导致大量请求穿透到Redis增加了序列化/反序列化开销。因此notes要求必须同时监控三级缓存命中率本地缓存、Redis、DB并计算“穿透率”DB请求数/总请求数。第二条是“缓存更新策略是否原子化”。常见的“先删缓存再更新DB”有风险若删缓存成功DB更新失败缓存为空DB有脏数据下次读取就会把脏数据写回缓存。notes推荐“更新DB成功后再异步删除缓存”并提供RocketMQ事务消息的实现模板确保DB更新和缓存删除的最终一致性。3.4 消息队列层消息不是发出去就完了而是要“送达且仅送达一次”消息队列的验证清单核心是“消息语义”。很多团队只关注“消息是否能发出去”却忽视“消息是否被正确消费”。notes里最关键的验证项是“消费者是否幂等”。我们曾因订单创建消息被重复消费导致同一个订单生成了多张支付单。根本原因在于消费者逻辑未做幂等校验。notes给出的硬性要求所有消费消息的业务代码第一行必须是幂等判断。例如订单消息的消费逻辑// 1. 根据消息中的order_id和biz_id业务唯一标识查询DB Order existingOrder orderMapper.selectByBizId(message.getBizId()); if (existingOrder ! null) { // 已存在直接返回不处理 return; } // 2. 创建新订单 createOrder(message);这里biz_id是业务生成的唯一ID如UUID与订单号无关确保即使消息重发也能识别出是同一笔业务。notes还强调“不要依赖消息队列的‘Exactly Once’语义它在分布式环境下极难保证。把幂等性做到应用层才是唯一可靠的方案。”4. 从“面试”到“生产”那些笔记里没写但决定成败的灰色地带系统设计笔记最容易被忽略的是那些无法画进架构图、不会出现在面试题里的“灰色地带”。它们不构成技术栈却决定了系统是稳定运行还是三天两头告警。这份notes的终极价值恰恰藏在这些“非技术细节”里——它们是我在生产环境里用一次次故障换来的认知。4.1 监控不是锦上添花而是设计决策的“照妖镜”一个经典误区先设计系统等上线后再补监控。结果往往是“监控覆盖不全故障时找不到根因”。这份notes强制要求监控指标必须在设计阶段就定义并作为验收标准的一部分。例如设计一个文件上传服务笔记里会明确列出必须监控的5个黄金指标1上传成功率HTTP 2xx/4xx/5xx比例2平均上传耗时P50/P95/P993单文件大小分布识别异常大文件4存储后端写入延迟区分上传耗时和存储耗时5存储空间使用率预警阈值设为85%。这些指标不是随便列的而是对应着5类典型故障成功率骤降指向网关或鉴权问题P99耗时飙升指向存储后端瓶颈大文件突增可能是爬虫或恶意上传存储写入延迟高说明磁盘或网络问题空间不足则预示着清理策略失效。我吃过亏早期没监控“单文件大小”结果一个用户上传了2GB的视频占满单节点磁盘导致整个集群上传失败。现在所有新服务的设计文档里“监控方案”章节和“架构图”章节一样重要且必须由SRE和开发共同签字确认。4.2 日志不是为了“看”而是为了“重建现场”日志设计常被当作开发收尾工作但它是故障排查的生命线。这份notes里日志规范比代码规范更严格。核心原则只有一条“任何一行日志必须能独立还原出完整的上下文”。这意味着1必须包含唯一trace_id全链路追踪ID2必须包含关键业务标识如order_id、user_id3必须包含明确的操作意图如“开始处理支付回调”、“校验签名失败”4必须包含结构化字段JSON格式而非纯文本。我们曾因日志缺少trace_id花费6小时排查一个跨服务调用失败问题——因为无法串联起调用链。现在notes规定所有日志框架Logback/Log4j必须预置MDCMapped Diagnostic Context在请求入口处注入trace_id和业务ID并在所有日志输出中自动携带。更关键的是notes要求“日志级别必须与业务重要性匹配”。例如支付成功必须是INFO级别并包含完整订单信息而“用户点击按钮”这类前端埋点日志必须是DEBUG级别且采样率设为1%避免日志爆炸。这看似是细节却是能否在海量日志中快速定位问题的分水岭。4.3 配置管理不是写死的字符串而是系统的“软肋”配置常被当作“不重要”的部分但它是系统最脆弱的环节。一份配置错误可能让整个集群雪崩。这份notes把配置管理提升到架构设计高度并列出三大死穴1配置热更新所有影响运行时行为的配置如限流阈值、超时时间、开关必须支持不重启生效。我们曾因修改一个Redis连接池大小不得不滚动重启所有服务导致服务中断15分钟。现在notes要求所有核心配置必须接入Apollo或Nacos且提供管理后台实时修改2配置灰度发布新配置上线必须先在1%流量上验证。笔记里详细记录了如何用Spring Cloud Gateway的Predicate组合实现“按Header灰度”3配置变更审计谁在什么时候修改了哪个配置修改前后的值是什么必须有完整审计日志。我们曾遭遇一次神秘的性能下降最终发现是运维同事误将数据库连接池最大连接数从100改成10——没有审计日志根本无法追溯。现在notes规定所有配置中心必须开启操作审计并与企业微信机器人联动每次变更实时推送告警。4.4 容灾演练不是“演”而是“练”出肌肉记忆最后也是最常被忽视的一点容灾方案必须定期演练且演练必须真实。很多团队的容灾文档写得天花乱坠但从未真正执行过。这份notes里容灾演练不是“计划”而是“季度强制任务”。规则很残酷1演练必须关闭真实服务如停掉主库、断开某机房网络2必须由一线开发和SRE共同参与而非仅由运维操作3必须记录从故障发生到业务恢复的全程时间并分析每个环节耗时。我们第一次演练“数据库主库宕机”从发现告警到切换完成花了47分钟远超SLA承诺的5分钟。复盘发现70%时间花在“确认是否真宕机”和“找负责人审批”上。于是notes新增两条铁律1所有关键服务必须配置自动故障检测和切换脚本如MHA for MySQL人工干预仅用于最终确认2建立“战时通讯群”演练开始即全员禁言只允许发送标准化指令如“/switch-db primary-down”。现在同样的演练平均恢复时间已压缩到3分12秒。笔记里写着“容灾不是为了证明方案可行而是为了暴露方案不可行的地方。每一次演练的失败都是下一次生产的成功。”5. 从“个人笔记”到“团队契约”让设计能力沉淀为组织资产一份高质量的system-design-notes最终价值不在于作者个人而在于它能否成为团队的“设计契约”。它把模糊的“经验”转化为清晰的“规则”把依赖个人英雄主义的救火变成可预测、可复制的工程实践。这份notes的终极形态不是一份静态文档而是一个活的、迭代的、嵌入研发流程的系统。5.1 设计评审Checklist把笔记变成会议议程我们把notes里的核心验证点提炼成一份15项的《系统设计评审Checklist》。它不再是评审会上的“自由讨论”而是逐项打钩的强制流程。例如评审一个新服务时主持人必须按顺序提问1“你的QPS预估依据是什么是否做过压测”2“数据库分片键是什么是否会导致热点”3“缓存穿透防护方案是什么是否验证过”4“消息消费是否幂等请展示代码”。如果任意一项无法当场回答评审即终止设计者需补充材料后重新申请。这个Checklist最大的作用是把“我觉得有问题”变成“你没满足第7条”。它消除了主观判断让评审聚焦在可验证的事实。我亲眼见证推行Checklist后团队设计返工率下降65%线上重大故障中因设计缺陷导致的比例从42%降至9%。5.2 架构决策记录ADR为每个选择留下“判决书”笔记里最珍贵的不是“做了什么”而是“为什么这么做”。为此我们强制推行ADRArchitecture Decision Record制度。每个重大设计决策如“选择Kafka而非RabbitMQ”、“采用分库分表而非读写分离”都必须撰写一份ADR文档包含1决策背景要解决什么问题2备选方案至少列出3个3评估标准性能、成本、团队熟悉度等4最终选择及理由量化对比5后续验证计划。这份文档不是存档而是嵌入Git仓库与代码共存。当新人接手项目时第一件事不是看代码而是读ADR——它告诉他为什么这个服务要用gRPC而不是REST为什么数据库索引要这样建。ADR让设计不再是个体的直觉而成为团队共享的认知资产。我们曾因一个老服务的ADR缺失导致重构时误判了技术债多花了3周时间。现在所有ADR都要求必须由至少两名资深工程师联署且每季度回顾一次评估当初的决策是否依然成立。5.3 技术雷达让笔记成为团队的技术罗盘最后这份notes进化成了我们的“技术雷达”。它不再只是文字而是一个动态的、可视化的技术选型指南。雷达分为四个象限1Adopt采用团队已验证、推荐在新项目中使用的方案如Spring Cloud Alibaba、Prometheus2Trial试用已在小范围验证、鼓励尝试的方案如eBPF网络监控3Assess评估值得关注、但尚未验证的新技术如WebAssembly边缘计算4Hold暂缓因成熟度或生态问题暂时不推荐的方案如某些小众NoSQL。每个象限的条目都链接到对应的notes页面包含详细评估报告、落地案例和避坑指南。技术雷达每季度更新由架构委员会投票决定。它让技术选型从“个人喜好”变成“集体共识”让新人能快速找到“团队认可的最佳实践”也让技术决策有了可追溯的依据。当一个工程师提议引入新技术时第一句话不再是“我觉得这个好”而是“请看技术雷达的Assess象限这里有我们的初步评估”。我始终相信系统设计能力不是天赋而是习惯。它藏在每一次对“为什么”的追问里藏在每一次对“验证”的坚持里藏在每一次对“灰度”的敬畏里。这份notes就是我用十年时间把那些散落在故障报告、深夜复盘、模拟面试中的碎片一块一块拼起来的镜子。它照见的不是完美的答案而是我们如何一步步把混沌的需求变成可运行、可维护、可演进的系统。如果你正在这条路上愿这份notes成为你口袋里那把随时可用的螺丝刀——不大但够紧每一颗关键的螺丝。