返回实用指南

系统设计面试:用边界、估算与故障推演组织方案

从需求澄清、容量估算、架构权衡到故障边界和上线检查,构建一份能解释假设并接受追问的系统设计答案。

阅读收获

完成一份带假设、故障边界和发布检查项的系统设计答题骨架。

发布日期
更新日期
审核人
TalentToCash 内容审核

来源标记(仅供核验,不提供站外跳转)

  • https://sre.google/sre-book/launch-checklist/

完成本文后,你将得到一份系统设计答题骨架:先澄清需求,用可替换的变量估算容量,再解释架构取舍,随后推演故障边界,最后用上线清单检查遗漏。文中对发布准备的事实背景来自 Google SRE 图书中的 Launch Coordination Checklist;其余答题顺序、问题模板和演练方式是本站编辑部的组织方法。该清单是生产发布协作材料,不是面试评分表,本文不会把它说成招聘标准。

系统设计题没有唯一架构图。面试官通常通过不断补条件,观察候选人能否保持目标、假设、状态和风险的一致。答案最容易失败的地方不是少画了某个组件,而是边界漂移:一开始说只处理文本,后面默认有大文件;一开始允许最终一致,后面又要求每次读取都立即最新;做了容量估算,却没有让估算影响分区、缓存或降级选择。

需求澄清:先确定系统承诺什么

先问功能边界:谁发起请求,核心对象是什么,最重要的读写路径是什么,哪些能力明确不做。再问质量边界:允许多旧的数据,失败后能否重试,是否要求顺序,哪些操作必须幂等,哪些数据需要审计或删除。最后问环境边界:已有数据库、消息系统、身份体系和地域要求是什么。

澄清不是把所有问题抛回面试官。你可以提出默认假设并等待修正,例如:“若没有额外要求,我先按单地域、文本元数据、读多写少设计;多地域和大文件作为扩展讨论。”每个默认值都要能在后续被替换。对方给出新条件时,明确指出哪部分设计随之变化。

把需求写成三类:必须满足、期望改善、暂不覆盖。必须满足决定正确性,期望改善决定优化方向,暂不覆盖防止方案无限膨胀。安全、隐私和权限不应被放到最后一句“再加鉴权”,因为它们会改变数据模型、缓存键、日志与删除流程。

容量估算:让变量推动设计而不是表演算术

容量估算的价值在于发现数量级和瓶颈,不是猜出一个看似专业的数字。可以定义变量:日活跃主体为 (U),每个主体每天平均写入 (W) 次,单条持久化大小为 (S),读写峰值系数为 (P),保留天数为 (D)。则日写入量可写为 (U \times W),基础存储量近似为 (U \times W \times S \times D),再单独考虑索引、副本、日志和版本带来的空间。

这些公式只有在口径清楚时才有意义。平均值不能代替峰值,业务对象大小不能直接当作物理存储大小,请求数也不等于下游调用数。估算后要明确它改变了什么:是否需要分区,单库是否够用,缓存能否容纳热点集合,队列积压多久仍可恢复,网络与第三方配额是否成为约束。

不要声称某个组件天然能支撑固定并发,也不要背诵未经来源验证的性能数字。面试中可以说“我需要通过基准测试确定单实例能力,先用变量表示”。如果对方给出量级,再把它代入;如果没有,就给高低两个情景,并说明设计拐点在哪里。

架构权衡:围绕状态、路径和责任画图

先画最小闭环:客户端或调用方、入口、核心服务、权威数据源。沿着一条写路径说明校验、幂等、持久化与响应;沿着一条读路径说明查询、缓存和权限过滤。只有当明确问题出现时,再加入队列、搜索索引、对象存储或分片。组件越多,故障组合和运维责任越多。

每个新增组件都回答四问:它解决哪个约束;保存什么状态;失败时谁感知;恢复时如何对账。异步队列可以隔离峰值,但调用方需要知道“已接收”不等于“已完成”,系统也需要处理重复投递、积压和永久失败。缓存缩短读路径,但需要定义权威来源、过期和穿透。搜索索引提高检索能力,但不能被默认为交易事实。

架构取舍要成对表达。同步与异步、强一致与最终一致、预计算与查询时计算、集中式与分区式,都没有脱离场景的赢家。先说选择,再说得到的收益、引入的代价和撤销条件。对团队不熟悉的基础设施,学习和运维负担也是代价。

系统设计演练:从文档处理状态到可恢复闭环

下面是一个假设演练,不是实际企业架构或性能案例。题目是设计“用户提交文档,后台提取内容并展示处理状态”的最小系统。

**第一步,锁定范围。**假设只讨论已获授权用户提交文档、查看本人任务状态和读取结果;文档格式、大小、保留期与敏感级别由题目进一步给定。暂不设计公开分享和协同编辑。上传成功的承诺是“任务已持久化”,不是“处理已完成”。

**第二步,定义状态。**任务可以有待处理、处理中、成功、可重试失败和终止失败等状态,但具体状态机要防止任意跳转。文档原件与任务元数据分开存放,任务记录保存所有者、对象引用、当前状态和版本。客户端用任务标识查询,但服务端仍须按所有者做授权判断。

**第三步,设计路径。**入口完成身份、格式和配额校验后,先持久化对象与任务,再把任务交给工作进程。工作进程领取任务时使用幂等条件,处理成功后写结果引用并更新状态。若队列消息重复,状态条件阻止同一版本重复提交结果。若处理超时,任务进入可诊断状态,而不是永远显示处理中。

**第四步,用估算选择拐点。**以 (U、W、S、P、D) 表示主体数、提交频率、文件大小、峰值与保留期。对象存储容量由提交量和保留期推动,工作进程数量由峰值任务到达率与单任务处理时间推动,状态查询压力决定是否需要短期缓存。没有真实基准时不填造吞吐数字,而是说明要测哪些量。

**第五步,推演失败。**对象保存成功但任务记录失败时,需要清理孤儿对象;任务已记录但消息未发出时,需要事务外盒或定期扫描等补偿思路;工作进程中途退出时,租约或超时机制使任务可重新领取;结果写入后状态更新失败时,需要对账。每条补偿都要避免越权读取和重复副作用。

这套演练的重点是承诺、状态和恢复闭环。换成图片处理、报表生成或通知任务时,组件可能变化,但检查方式仍可复用。

故障边界:说明系统如何变差

故障边界不是一句“多副本高可用”。按层枚举:单进程、单机器、网络、存储、队列、依赖服务、地域和人为配置。对每一层回答检测信号、影响范围、自动动作、人工入口和恢复后的对账。超时、重试、限流和熔断要一起讨论;无限重试会放大故障,过短超时会制造假失败,缺少幂等会让重试产生重复副作用。

Google SRE 的发布协调清单把架构草图、流量与容量估计、负载和端到端测试、失效切换、后端死亡检测、超时重试、备份恢复、监控、安全审查、分阶段发布、外部依赖和操作流程放在同一检查面。这支持一个重要事实:可上线性不只是代码是否运行,还包含容量、依赖、观测、安全和恢复准备。本文将这种检查面借来提醒面试答案,但具体组织方式是编辑方法。

降级必须保护核心承诺。例如搜索不可用时可以暂时只支持精确查询,推荐不可用时返回基础内容,异步处理变慢时保留已接收状态。但如果权限服务无法确认身份,不能为了可用性默认放行。指出“哪些能力可降级、哪些必须失败关闭”,比泛泛说“保证高可用”更有工程意义。

上线清单:把设计转成可操作检查

  • [ ] 已写清架构图、请求类型、核心状态和每个组件的责任人。
  • [ ] 已用变量估算流量、存储、带宽和峰值,并标出需要实测的未知量。
  • [ ] 已完成关键路径负载测试和端到端测试,结果能关联到设计假设。
  • [ ] 已推演实例、网络、后端和依赖失败,定义超时、重试、限流与降级。
  • [ ] 已准备监控、告警、日志关联和“监控本身失效”的发现办法。
  • [ ] 已检查身份、授权、敏感数据、审计与上线前访问控制。
  • [ ] 已明确备份、恢复、对账、回滚和人工操作流程,并安排演练。
  • [ ] 已设计小范围发布、观察窗口、停止条件和逐步放量责任。
  • [ ] 已登记第三方依赖、配额、故障表现和避免压垮对方的保护措施。

适用边界与表达限制

Google SRE 清单来自特定组织和历史语境,不能直接复制成任何公司的完整发布制度,更不能声称它是面试官统一使用的评分表。本文没有提供真实容量基准,也没有替代安全、合规、数据治理或云厂商文档。实际系统必须依据业务风险、团队能力、部署环境和当前产品文档重新验证。

系统设计面试的时间有限。不要为了覆盖清单而一次性念完所有检查项;先围绕题目关键风险展开,再用清单补漏。题目如果是单机组件设计,过早讨论多地域会偏离重点;题目如果涉及资金、医疗或身份数据,则必须更早澄清正确性和权限。

下一步:选一道系统设计题,用一页纸写出“需求假设—变量估算—最小架构—三条故障路径—上线检查”,再请同伴只改变一个条件,标记你的架构中哪些部分必须随之修改。