[面试][系统设计]如何设计一个像 Facebook 的社交平台

擅长嘴炮沟通的人在这个环节有较多优势。

其实前面 10 几篇文章的内容都是系统设计的一环,只是问题的方向是从你过往的履历、技术或是面试公司的需求出发,透过询问细节来评核你技术的硬实力。

再确认求职者的硬实力过关後,有些面试官会给你一个情境来做系统设计;然後依据你在这道题目上的应对进退,决定要给你 Junior 还是 Senior 的职称

如果你面试的职缺是 Tech Lead,这题回答得不好有高机率直接出局。

大纲

  1. 初探系统设计

    • 1.1 Junior 跟 Senior 工程师的差异
    • 1.2 系统设计的题目来源
    • 1.3 面试官在找的是同事
  2. 如何设计一个像 Facebook 的社交平台

    • 2.1 缩小问题范围,确认具体需求
    • 2.2 先提出一个简单的解决方案
    • 2.3 提出减少耗能的解决方案
    • 2.4 从自己擅长的面向切入
    • 2.5 不要有预设立场
    • 2.6 主动提出不同设计的优缺点
  3. 衍伸问题

    • 3.1 你有使用过 Mind Map 跟 Sitemap 吗?它们的使用时机是?

1. 初探系统设计

笔者在第一次遇到系统设计的问题时表现得很差,因为我把它当成一个技术性的问题,所以不停的在输出自己的想法及观点,面试完的当下还觉得自己表现的超棒,肯定会拿到 Offer。

果然在两天後收到 Offer Get 的信件,但核薪结果没有到达自己的期待;当时我并不了解自己在哪个环节犯了错,於是向人资询问主管对我的评价,我收到的评价是:「技术完全没问题、经验丰富、自我学习能力高;但在系统架构的设计上能力稍显不足,主观思维太多。」

在这之後我才知道面试有「系统设计」这个类型的题目,也明白当时的回答并不是面试官期待的答案。

1.1 Junior 跟 Senior 工程师的差异

Junior 工程师在看到问题後会想直接提出解决方案;而 Senior 工程师则会先厘清问题,从整体架构去思考

会有这样的差异是很正常的,因为 Junior 工程师在入职後,往往是接受任务分配的一方,所以他们已经习惯「收到问题 → 解决问题」的作业模式;很少人会去思考为什麽要这样做、能不能这样做,以至於可以完成交办的任务,却缺乏对整体架构的思维。

而 Senior 工程师除了要写程序外,有时还要跟 PM 讨论需求、规划系统架构、分配工作给 Junior 工程师、帮 Junior 工程师 Debug;有些工程师讨厌做这些事情,因为会耽误到自己写程序的时间,但正因为这些事情让他有更完整的架构思维与沟通能力


1.2 系统设计的题目来源

虽然系统设计的范围很广,但面试官爱考的就大概就是以下几种:

  • 经典面试题
    很多面试官都是去题库里面找题目,我这里也是建议读者先熟悉题库;透过反覆练习题库,除了掌握基本盘外;在面对没有接触过的系统也能做到基本的应对进退。
  • 面试公司的系统
    有些知名企业喜欢向求职者询问:「如果是你,会如何设计我们公司的系统?」
    这个问题除了考系统设计外,其实也是想知道求职者对面试公司的系统了解有多深
  • 你履历上的技能
    像是笔者在履历上有网页爬虫的经历,面试官就会以此询问笔者:「如何设计一个网页爬虫的系统?」

备注:
每个面试官在意的细节都不一样;有些题目除了要系统设计外,他还要你提供不同方案的人力资源配置、功能时程预估、所需硬体资源...,要你设计一套可以让组织运转的流程。
如果没有一定的实务基础,面对这些延伸的问题基本没有招架之力。


1.3 面试官在找的是同事

问题走向完全看面试官的喜好,因为没有固定的解答,所以回答是否被接受也是看你跟面试官频率是否契合

今天面试官要找的是同事,在确认技术过关後;他想透过这个关卡更进一步了解求职者:

  • 是否具备分析问题的能力。
  • 会经过讨论再做出设计,而不是一开始就有许多预设立场。
  • 能够清晰阐述自己的策略。
  • 沟通时双方在同一个频率,不会出现鸡同鸭讲的状况。
  • 能评估自己提出方案的优缺点,并提出可行的优化方案。

与其说是考试,更像是同事间在讨论一个议题;有时也会遇到你认为自己的方案没问题,但面试官就是觉得不可行的状况;此时你可以先了解面试官顾虑的点,可能真的有自己忽略的细节。

有时面试官的技术能力未必高於求职者,也许你提出的方案更好,但因为已经超过面试官知识范围所以不被采纳;此时并不建议坚持己见,你可以说:「也许有我忽略的细节,您的考虑应该是对的。」然後转移到下一个话题

如果你遇到一个自己完全不熟悉的领域,连回答的头绪都没有,请跟面试官讨论你想解决的问题,并说明为什麽会卡住,千万不要不懂装懂瞎掰答案;多跟面试官互相分享彼此的想法,面试官自己也很清楚求职者是不可能在短时间内给出完美的答案,面对自己不熟悉的议题,就算有不会知识也是很正常的。

  • 系统设计不只是单纯的考试,而是评估你在工作上会如何讨论问题。
  • 双方有来有往聊得越开心,就算你的回答有犯错也容易被忽略。

会录取的求职者未必技术能力最好,但绝对是在面试过程中沟通流畅的


2. 如何设计一个像 Facebook 的社交平台

2.1 缩小问题范围,确认具体需求

大部分主管在交代事情时,只会给一个方向,并不会把细节说清楚;所以面试官也是想透过这个问题来了解在未来交办工作时,你会如何面对。

  • 缩小问题范围
    Facebook 是一个经历十几年改版、无数菁英灌注青春与热血的系统,它所提供的服务实在是太多了,所以要先确认问题回答的方向,比如说:「Facebook 有提供蛮多种服务的,像是发文动态、Messager、广告系统;我们要先从哪一块来做讨论?」
  • 不要急着提出解决方案
    当年笔者没搞清楚状况,把它当成高流量架构设计的问题;直接丢出一堆像是 Load Balance、Repliaction、DB Sharding...的技术方案;我当时说的很开心,但回答的内容完全偏离了面试官想要了解的方向

    使用什麽技术可以等需求确定後再讨论,如果一开始在分析问题时就走偏了,那後面再多的努力也没有用。


2.2 先提出一个简单的解决方案

假设面试官把问题缩小到打造一个 Messager 的系统,那核心功能就非常明确;此时你只要简单叙述设计概念就好;不要急着说出使用 Node.js + Socket.io + MongoDB 这些工具来打造系统。

  • 简述基础解决方案
    我们会需要一个聊天服务器来处理讯息间的沟通,当用户发送讯息时,讯息会先传送到服务器并储存;如果接收方在线上就直接传送讯息给他,如果不在线就透过推播通知
    在 UI 介面上,使用者发送讯息成功时会有时间戳记;当接收方点开讯息时也会有已读的标记

通常考题都会涵盖「前端、後端、资料库」的设计;这样面试官才能依照自己在意的点深入询问。


2.3 提出可以减少耗能的可行方案

资源永远是有限的,更高的硬体规格代表更多的预算,此时就需要 trade-off(权衡)

接着让我们从资源消耗的角度来探讨 Messager 这个系统中,好友上线显示绿灯的功能要如何设计。

最简单的做法是当用户一上线,就向所有好友发送上线通知;但这个设计在系统成长到百万用户,且特定时段上线的活跃用户数量高达 30 万时,这种发送通知的方法对资源的消耗极大

  • 有什麽方式可以减轻资源消耗?
    很多人打开 Messager 只是简单回覆讯息就关掉,所以系统其实没必要爲刚上线的用户立刻发送通知;我会建议把发送上线通知的策略改为显示活跃用户,可能要在线 5 分钟以上再发送通知;透过减少请求的次数来降低对系统资源的消耗

2.4 从自己擅长的面向切入

在提出基础的解决方案後,题目就会往细节发展,此时你可以主动向面试官确认一些系统需求,假设你擅长大流量高并发的议题,你就故意问面试官:「这个系统在设计上要考量到大流量以及高并发的问题吗?

主动引导面试官将话题转向自己擅长的领域是很重要的;但如果面试官对这个议题没有兴趣,千万不要自顾自的一直讲

如果你对某个领域不擅长就不要挖坑给自己跳,假如你主动提及资料库相关问题,面试官可能就因为你履历上有 MySQL 跟 PostgreSQL 的经验,而询问你两者的优缺点及使用时机,如果你答不出来反而会被扣分。


2.5 不要有预设立场

Messager 系统除了传送讯息这个基础功能外,还有建立聊天群组、回覆特定讯息、移除讯息、对讯息传送表情符号...等众多功能。

如果你打算在这些功能上开辟战场,请先询问面试官是否需要这些功能;而不是没有经过沟通,自己觉得理所当然就直接开始设计。

经验分享
在系统开发上,如果你要做的功能在需求规格以外,一定要先跟 PM 沟通;你认为必要的功能对客户来说可能根本不需要,甚至系统有可能因为多出来的功能而产生无法预期的 Bug;千万不要自作聪明


2.6 主动提出不同设计的优缺点

如果面试官把话题带到 DB Sharding 上面,比如:「随着用户成长,储存用户的 Table 资料量太大,效率越来越低,有什麽解决方案吗?」

笔者会用下面的角度来回答:
考虑到用户数量会持续成长,为了减轻资料库的负担,我会将这个 Table 切分到多个资料库来分散压力,这边提供两种切分策略:

  • Range-based partitioning
    第一种是挑选一个合适的栏位作为切分条件,像是以用户的「年龄」做为切分条件;不过使用这种方式可能会造成不均匀的 Server load,因为每个年龄段的用户数量不同。
  • Hash partitioning
    为了解决 Server load 不均匀的问题,第二种方案则是挑选一个栏位用 Hash Function 计算出一个值,用这个值来决定资料要放到哪个资料库。

    可以采用 Consistent Hashing 让资料均匀分布在不同 DB;这个方案在 DB 数量有增减时,也能尽量避免原有的 Key 被重新分配。

系统设计没有标准答案,如果你有能力提出多种解决方案,并能说出各自的利弊是非常加分的。


3. 衍伸问题

3.1 你有使用过 Mind Map 跟 Sitemap 吗?它们的使用时机是?

考点:设计系统架构时的辅助工具

  • Mind-Map
    在专案做需求访谈时,我会先透过 Mind Map 来帮助发想与记录想法,透过这张图即使开会偏离重点也可以快速拉回;在会後我会透过它向同事说明需求的关联性、以及一些功能的限制条件,让他们快速理解这个专案的目标。
  • Sitemap
    在需求明确後,我会用 Sitemap 规划系统架构,设计页面之间的关联性与阶层,完成流程上的模拟;并检视规划是否有下列问题:
    • 如果需要 SEO 的页面被埋得太深就要重新规划,避免 Google 爬虫不到。
    • 检查是否有规划不良导致的孤儿网页。

      孤儿网页:系统没有连结可以抵达的网页。


笔者碎碎念

即使经验丰富,面对一个从未思考过的问题,也很难提出合适的设计;这边建议读者可以透过以下方式,有意识地培养自己系统设计的能力:

  • 上网找题库,吸收他人在系统设计上的经验。
  • 找 Mentor 做模拟面试,熟悉答题方向。
  • 在闲暇时思考知名的系统是如何设计出来的(ex:Youtube、Google、Twitter...)。

感谢大家的阅读,如果喜欢我的文章可以订阅接收通知;如果有帮助到你,按Like可以让我更有写文的动力,我们明天见~

参考资源

  1. 系统设计面试 6 个技巧|我面 Google 前的准备方法
  2. 软件工程师系统设计面试准备指南
  3. 系统设计面试(第一部分)
  4. donnemartin/system-design-primer
  5. 从 Sitemap 的应用,谈 SEO 的学习

我在 Medium 平台 也分享了许多技术文章
❝ 主题涵盖「MIS & DEVOPS资料库前端後端MICROSFT 365GOOGLE 云端应用自我修炼」希望可以帮助遇到相同问题、想自我成长的人。❞


<<:  CSS微动画 - Transform不一定是位移的最佳选择

>>:  DAY25 - 自学就像瞎子摸象,在未知的情况下试图拼出原貌

[Day15]汇总函数(分组函数)

汇总函数是以多笔资料列为基础,输入的资料列经过函数运算後,一组只会输出一个值,基本特性如下: 可将一...

D1 - start

各位夥伴这个热血的30天挑战又来了 不免俗的第一天开赛就是来分享一下这心路历程XDD 8月本来想说今...

Day 30 - Summary

本文将於赛後同步刊登於笔者部落格 有兴趣学习更多 Kubernetes/DevOps/Linux 相...

用 Python 畅玩 Line bot - 14:Flex Message(一)

有些非官方 line bot 会有像(图一)的 message,让使用者可以有较弹性的方式去使用该 ...

[Day21] Esp32用STA mode + AHT10

1.前言 前两天看完AHT10 + APmode 那篇後,是不是对这篇抱有更大的期待与兴趣了,因为S...