系统设计面试是考察一个工程师水平和资历的非常有效的方式。尽管我们网上能找到很多设计面试相关的准备工作以及不少的面试题目,但是讲述真实面试过程的资料寥寥无几。
在这篇文章里,我将分享一些用分布式系统面试高级工程师时的经验。如果你想掌握面试的秘诀,就继续读下去,因为准备面试的最好方法就是了解面试官是如何思考的。
注意一点:这种类型的面试仅适合考察有一些业界经验的工程师,应届生或刚工作不久的工程师或许还不具备通过这类面试的能力。
选择一个你熟悉的系统
面试,通常是一个开放式的对话,在这个过程中应把应聘者当成你的同事,针对一个特定的问题与其共同探讨,让TA在1小时左右内设计出一套方案来解决它,来考察TA的问题解决(problem-solving)的能力/经验。
面试中讨论的目标系统最好是你的团队正在使用或曾经使用过的系统,不仅因为你对它最熟悉,还可以让应聘者提前了解未来公司的项目。别忘了,面试不仅是你评估别人,应聘者也同时在评估公司。
选用你熟悉的系统的另一个好处就是:之前你已经花了很多功夫来内化目标问题的解空间、扩展时所需考虑的限制、各种考量间的妥协以及高可用的容错方案,因此对这些可能出现的问题、以及解决方案你或你的团队已经有了些想法以及尝试,准备起面试来也就自然省力一些。而且说不定,应聘者还能帮你发现以前忽略的问题,这是个双赢。
不论如何,都不要让人回答:如何设计实现个Twitter,(除非你就在Twitter的核心团队工作),或类似的题。
如果你在做一个酒店订购在线电商平台,而问了应聘者如何设计一个类似Twitter的系统,那就等于告诉对方,目前所提供的这份工作一点创新含量都没有,而且你也对当前的项目毫无兴趣,而这尤其对于资深的工程师,相当于劝退提醒了。
肯定有人会问:“如果我没有类似Twitter的那种大规模分布式的问题呢?”——我理解,但其实没关系,Twitter只是设计分布式系统要解决的诸多问题之一,再说并不是每个企业都像Twitter一样——要支持百万并发以上的用户访问——需要实现如此高难度的扩展性。
从小规模的设计开始
面试开始的前几分钟,可以先简单和应聘者聊聊过去的项目经验,了解他们自认为的优势与不足,然后再抛出事先准备好的面试问题。记得先在白板上画出接下来将讨论的目标系统的基本框架,这会让应聘者更加放松,反之如果上来什么信息都不给,仅是一个空白板,那只会让对方紧张。
在向面试者展示TA将设计的系统时,从简单小规模的架构开始,我们需要先确保对方跟上节奏,后面再深挖可扩展性等。同时注意,不要把所有的特性需求一股脑地全抛出来,要给应聘者足够时间边听边提问,看TA是否真的理解了你的问题全貌,然后再开始深入解决也不迟。
最后,让应聘者讲一讲自己的系统设计思路。不要光听着,要试着跟对方聊起来,去挖掘他们的思考路径与模式。在这一步里,不必去追究到细节如某一组件的设计以及技术点,要给对方足够空间去描述完整的体系。
如果你觉得方案里的不确定的部分太多,可以问问对方有没有办法在不影响解决的前提下,去掉一些特定的组件,让他们自己来调整折衷。例如:为什么必须选择加一个NoSQL存储,只用一个SQL关系型数据库是否也可以?
面试开始30分钟后,白板上应该有初步的框架了。
逐步提升问题规模
既然应聘者已经有了初步的框架设计,该进一步提升规模了。比如提升每秒并发访问量(RPS),或者增加数据摄取量的规模,或者任何问题相关的指标提升。不论原始设计是什么架构,我们总是能通过在某些方面提升规模这一思路,而找到需要进一步调整优化的系统潜在瓶颈。
这时可以问问应聘者,TA觉得随着规模增加而导致系统瓶颈有可能出现在哪里。如果他们能自己指出来并给出解决方案,那肯定是最好了。当他们找到系统瓶颈时,协助他们探索方法。然后重复这个反复迭代的过程:每次探索可能性最大的瓶颈并解决——因为每次优化调整设计,最大的瓶颈也会可能改变,需要不断作出新的折衷与调整。在每个回合里跟应聘者讨论变动是什么,并分析TA做这些改动的原因以及背后的原理。
指出他们的容错性考虑不足之处,并让他们预测这些组件或是链路失效后,系统会出现什么问题。考量TA是否能快速高效地发现潜在的涉及高可用/容错相关的瓶颈,比如常见的单点失效问题(SPOF)等。并通过观察他们解决问题的是否优雅,你能很容易看出对方的经验和能力,因为这些系统问题都是你经历过并解决过的。
面试进行到50分钟左右,你们应该沟通过可扩展性和高可靠性的相关话题了。如果时间足够,可以从TA地设计里选取一个组件或分层,并逐步细化地深入验证考量。例如,应聘者的设计里需要包含多数据副本,就让TA谈谈数据一致性的看法,并指出如何具体保证。
这类似于问:在你的搜索框中输入网址“example.com”,然后会发生什么?只不过这个问题需要更针对于你们谈论的目标系统。如果你正在招聘的是高级系统工程师,应该要求他们对TCP协议、分页机制、一致性模型等理论持有深入的见解,这些技能对于调试和优化复杂系统都是必备的。
面试快结束时,对于应聘者的强项和不足、面对开放式问题时的解决思路,你应该很了解了。一个经验丰富的应聘者应该是这样的:迅速开场,流畅地建好系统,并指出潜在瓶颈/失效点;能够清晰的表达每一步决策的理由,并列出这个设计中全部的折衷考量。面对优秀的应聘者时,面试的过程会更像是向他们学习的过程。
最后总结
系统设计的面试是考察应聘者问题解决能力的高效方法。画出盒线相连的流程图是必要的,但通常不是最有挑战性的。最难的部分是需求理解、瓶颈定位、以及折衷权衡。而这些方面的探索的过程需要进行反复沟通和讨论,这也侧面反应了应聘者的软实力。比如他们能清楚的表达自己吗?他们能否读懂对方的建设性反馈?而这往往也非常重要。
原文作者:Roberto Vitillo,原文链接。