第三章:系统设计面试框架 (A Framework For System Design Interview)
你刚刚获得了心仪公司的现场面试机会。招聘协调员发给你当天的面试安排。你浏览着面试表单,感觉还不错,直到你的目光停留在一个环节——系统设计面试。
系统设计面试常常让人感到害怕。面试问题可能会非常笼统,例如“设计一个知名产品X”。这些问题模棱两可,且似乎过于宽泛,令人无从下手。你的担忧是可以理解的。毕竟,如何能在一小时内设计出一个知名产品,而这个产品可能需要数百甚至上千名工程师才能完成?
好消息是,没人期望你真的做到这一点。现实中的系统设计非常复杂。以谷歌搜索为例,虽然看似简单,但其背后的技术量是惊人的。如果没人期望你在一小时内设计出一个真实世界的系统,那么系统设计面试的意义是什么呢?
系统设计面试模拟的是现实中的问题解决场景,通常是两位同事合作,面对一个模糊的问题,协作出一个符合目标的解决方案。问题是开放式的,且没有完美答案。最终设计的成品并不如设计过程中的工作表现重要。这让你有机会展示自己的设计能力、为设计选择辩护、并以建设性的方式回应反馈。
让我们反过来看,想象面试官走进会议室时,脑子里在想什么。面试官的主要目标是准确评估你的能力。她最不希望的情况就是面试进展不顺利,导致信号不足,无法做出明确的评价。那么,面试官在系统设计面试中究竟看重什么呢?
许多人认为系统设计面试只是考察一个人的技术设计能力,实际上,它远不止如此。一次有效的系统设计面试能够清晰展现一个人的协作能力、在压力下工作的表现以及如何建设性地处理不确定性。提问的能力也是一个重要的技能,许多面试官会特别关注这一点。
优秀的面试官还会留意一些“红旗”警示。过度设计是许多工程师的通病,他们在追求设计纯粹性时忽略了取舍。这些工程师往往没有意识到过度设计系统的隐性成本,许多公司因此付出了沉重的代价。在系统设计面试中,你绝不想展示这种倾向。其他警示信号还包括思维狭隘、固执己见等。
在本章中,我们将介绍一些有用的提示,并提出一个简单且有效的框架,帮助你解决系统设计面试中的问题。
有效的系统设计面试四步流程
每次系统设计面试都是不同的。一场优秀的系统设计面试是开放式的,并且没有通用的解决方案。然而,任何系统设计面试都有一些共同的步骤和核心内容需要涵盖。
第 1 步:理解问题并确定设计范围
“为什么老虎会咆哮?”
教室后排有一只手举了起来。
“是的,Jimmy?”老师回应道。
“因为它饿了。”
“非常好,Jimmy。”
从小到大,Jimmy总是班里第一个回答问题的孩子。每当老师提问时,班里总有一个学生喜欢抢先回答问题,不管他知不知道正确答案,而这个学生就是Jimmy。
Jimmy是个尖子生,他以快速答题为傲。在考试中,他通常是第一个答完题目的人,也是老师参加学术竞赛的首选。
不要像Jimmy那样。
在系统设计面试中,快速给出答案并不会为你加分。在没有彻底理解需求的情况下回答问题是一个严重的“红旗”信号,因为这场面试并不是一个知识竞赛,也没有所谓的“正确答案”。
因此,不要急于给出解决方案。放慢脚步,深入思考,并通过提问来澄清需求和假设。这一步非常重要。
作为工程师,我们喜欢解决难题并快速进入最终设计阶段;然而,这种方法很可能会让你设计出错误的系统。作为工程师,最重要的技能之一就是提出正确的问题,做出合理的假设,并收集构建系统所需的全部信息。因此,不要害怕提问。
当你提问时,面试官要么直接回答你的问题,要么要求你自己做假设。如果是后者,请将你的假设写在白板或纸上,这些假设可能在之后的设计过程中派上用场。
那么应该问哪些问题呢?通过提问来理解具体的需求。以下是一些可以帮助你入手的问题:
- 我们需要构建哪些具体功能?
- 产品有多少用户?
- 公司预计会扩展多快?在未来3个月、6个月以及1年内的预计扩展规模是多少?
- 公司使用什么技术栈?你可以利用哪些现有的服务来简化设计?
示例
如果你被要求设计一个新闻推送系统,你需要通过提问来澄清需求。你和面试官之间的对话可能会是这样的:
候选人:这是一个移动应用吗?还是一个网页应用?或者两者都有?
面试官:都有。
候选人:产品的最重要功能是什么?
面试官:发布帖子和查看好友的新闻推送。
候选人:新闻推送是按倒序时间排列还是按某种特定顺序排列?特定顺序意味着每个帖子会有不同的权重。比如,来自亲密好友的帖子比来自群组的帖子更重要。
面试官:为了简化,我们假设推送按倒序时间排列。
候选人:用户最多可以拥有多少好友?
面试官:5000个。
候选人:流量大概是多少?
面试官:每日活跃用户(DAU)有1000万。
候选人:推送内容是否可以包含图片、视频,还是仅限于文字?
面试官:可以包含媒体文件,包括图片和视频。
以上是一些你可以向面试官提出的示例问题。通过提问来理解需求并澄清模糊点是非常重要的。
第 2 步:提出高层设计并获得认可
在这一步,我们的目标是开发出一个高层设计,并与面试官达成一致。在这个过程中,与面试官合作是个不错的主意。
- 先提出初步的设计蓝图,询问反馈。把面试官当作你的队友,一起协作完成设计。许多优秀的面试官喜欢参与讨论并提供建议。
- 在白板或纸上绘制包含关键组件的框图。这些组件可能包括客户端(移动/网页)、API、Web服务器、数据存储、缓存、CDN、消息队列等。
- 通过简单的估算来评估你的设计是否适合规模要求。大声思考,必要时与面试官沟通是否需要做这样的估算,然后再深入设计。
如果可能的话,分析几个具体的使用场景。这有助于你构建高层设计,使用场景也可能帮助你发现尚未考虑的边界情况。
是否应该在这一步包括API端点和数据库模式?这取决于具体的问题。对于像“设计谷歌搜索引擎”这样的大规模设计问题,这可能过于低级;但对于设计一个多人扑克游戏的后台系统,这样的细节就很合适。与面试官沟通来确定设计的深度。
示例
让我们用“设计一个新闻推送系统”来演示如何处理高层设计。在这里,你不需要完全理解系统的工作原理,所有细节会在第11章中解释。
从高层设计的角度,系统可以分为两个流程:推送发布和新闻推送生成。
- 推送发布:当用户发布一个帖子时,相应的数据会被写入缓存/数据库,并且该帖子会被分发到好友的新闻推送中。
- 新闻推送生成:新闻推送通过聚合好友的帖子并按倒序时间排列来构建。
图3-1和图3-2分别展示了推送发布和新闻推送生成流程的高层设计。
第 3 步:深入设计
到了这一步,你和面试官应该已经完成了以下目标:
- 就整体目标和功能范围达成共识
- 勾勒出整体设计的高层蓝图
- 从面试官处获得高层设计的反馈
- 基于反馈,对深入探讨的领域有了一些初步的想法
你需要与面试官合作,确定并优先考虑架构中的关键组件。需要强调的是,每次面试都不一样。有时,面试官可能暗示她更关注高层设计;有时,对于高级候选人的面试,讨论可能集中在系统性能特性上,特别是瓶颈和资源估算。在大多数情况下,面试官希望你深入某些系统组件的细节。例如,设计一个URL缩短器时,深入探讨将长URL转换为短URL的哈希函数设计是个有趣的话题;而在一个聊天系统中,如何减少延迟以及支持在线/离线状态则是两个值得讨论的方向。
时间管理非常关键,因为很容易陷入琐碎的细节,而这些细节并不能展示你的能力。你需要展示给面试官有价值的信息,尽量避免进入不必要的细节。例如,在系统设计面试中,详细讲解Facebook新闻推送排名的EdgeRank算法就不太理想,因为这会耗费宝贵的时间,并且无法证明你设计可扩展系统的能力。
示例
到目前为止,我们已经讨论了新闻推送系统的高层设计,面试官对你的提议表示满意。接下来,我们将深入探讨两个最重要的用例:
- 推送发布
- 新闻推送获取
图3-3和图3-4分别展示了这两个用例的详细设计,具体细节将在第11章中解释。
第 4 步:总结
在最后一步中,面试官可能会问你一些后续问题,或者让你自由讨论其他补充点。以下是几个可能的方向:
- 面试官可能希望你识别系统的瓶颈,并讨论潜在的改进措施。永远不要说你的设计是完美的、没有可以改进的地方。总有改进空间,这是展示你批判性思维的绝佳机会,并能给面试官留下良好的最后印象。
- 向面试官概述你的设计思路可能会很有帮助,特别是当你提出了多个解决方案时。经过一场长时间的讨论,回顾设计有助于帮助面试官重新记起你提出的内容。
- 错误场景(如服务器故障、网络中断等)是值得讨论的。
- 运营问题也值得一提,比如如何监控指标和错误日志?如何部署系统?
- 如何应对下一次的扩展需求也是一个有趣的话题。例如,如果你当前的设计支持100万用户,如何修改以支持1000万用户?
- 如果有更多时间,你还会做哪些改进?
总结我们需要注意的事项(Dos and Don’ts):
Dos:
- 始终要求澄清,不要假设自己的假设是正确的。
- 理解问题的需求。
- 没有正确或最好的答案。为初创公司设计的解决方案与为拥有数百万用户的成熟公司设计的解决方案不同,确保你理解需求。
- 让面试官了解你的想法,保持沟通。
- 如果可能的话,提出多个方法。
- 一旦你和面试官对设计蓝图达成一致,深入讨论每个组件,优先设计最关键的部分。
- 和面试官交换想法。一个好的面试官会和你像队友一样合作。
- 永远不要放弃。
这些建议将帮助你在系统设计面试中更好地表现并给面试官留下深刻印象。
Don’ts
- 不要对典型面试问题没有准备。
- 不要在没有澄清需求和假设的情况下直接跳入解决方案。
- 开始时不要过于详细地讨论单个组件。首先给出高层设计,然后再深入细节。
- 如果遇到困难,不要犹豫要求提示。
- 再次强调,保持沟通。不要默默思考。
- 不要认为一旦你给出设计就结束了。只有在面试官说你结束之前,你都没有结束。要早频繁地请求反馈。
每一步的时间分配
系统设计面试问题通常非常广泛,45分钟或一个小时通常不足以覆盖整个设计。时间管理至关重要。每一步应该花费多少时间呢?以下是一个在45分钟面试中分配时间的粗略指南。请记住,这只是一个粗略的估计,实际时间分配取决于问题的范围和面试官的要求。
- 第一步:理解问题并确定设计范围:3 - 10分钟
- 第二步:提出高层设计并获得认可:10 - 15分钟
- 第三步:深入设计:10 - 25分钟
- 第四步:总结:3 - 5分钟
通过遵循这些指导原则,你将能更有效地应对系统设计面试,最大限度地展示你的能力和思考过程。