X扯闲篇
系统设计题目就是一个大坑 没有一个标准答案的意思就是面试官如果真跟你过不去随便挂人 跟玩儿似的。说答案的时候,总的来说,最注意把控的就是平衡细节的知识和大局的构架。什么意思?一,别有太多细节你自己说出来了你自己答不上,比如你说要用redis 结果redis数据放哪不知道。那就gg了。二, 别说一个细节说了十分多钟忘了之前到哪了。工程师就不能跟我一样,丢三落四的,就算你面试过了也一定做不了多好。勤看表不是问题,但是一定要有一个大概的感觉你每一个部分大概说多久,然后什么时候到哪了一定 一定 一定要有数。
结构 (我这四十几分钟要说什么)
有个培训机构叫太阁 他们用的方法是SNAKE 原则。啥意思啊?
Scenario - Necessary - Application - Kilobit - Evolve
先说哪里用得到,再说我们需要解决问题多大规模。然后说基本解里头Application里面都有啥,然后说说相对应的数据放哪里怎么放。最后这些都说完了(20-25分钟左右)来具体谈怎么让我的基本解在哪些方面做的更好。
还有个培训机构叫九章, 他们用的方法是4S原则,啥意思啊?
Scenario - Service - Storage - Scale
先说哪里用得到 要解决什么问题,然后说我们一个大系统对吧,怎么写出对应的micro services, 然后再说我们的数据放哪里怎么放,最后(也是20-25分钟后)说我们怎么样向上scale
这两个大家想明白了其实就是一回事。这俩都有版权 我都不能用,如果各位是随便过来看到的,也推荐大家两个都上一下 相辅相成很有用。
Scenario 场景
1. 问清楚自己要做哪些功能(也就是说,45分钟内不聊哪些功能)
2. 问清楚或者说清楚自己要handle多大用户量,面试官起码得给你确认这么几个信息,否则聊不下去。
- 一个是你平均每天handle多少用户
- 一个是你峰值(最多?不太精确但是形容一下)每天handle多少用户
3. 自己把自己要算的东西都算出来, QPS啊,存储size啊,不非得一口气全部算完,但是记住最基本的用户量,然后再说然后的。
Implementation 实现
4. 搭架子,我的系统要干嘛,为了做这件事情,我们需要什么组件,怎么安排。这里一切最简单,保证这个东西可以work,不要有明显的优化还不做。
5. 按照架子一个一个实现具体功能,如果发现有问题了,改改架子。记住。改架子的时候一定要想想别的东西动没动,动了,赶紧拿个纸记下来。数据放哪可以这里说可以分开说,这都不要紧。
6. 架子流程实现完了想想数据放哪里怎么放,那么些个数据库呢,好好挑挑。
Enhancement 提高
7.根据确认的问题或者优化点慢慢优化。这里的话,不懂就说不懂。为啥?基本分已经有了,大好局面来之不易,千万不要不懂装懂暴露问题。比如你之前说的都挺好,然后到优化了把load balancer放到dispatch service还要靠前端的地方,这不扯么?
具体结构怎么安排我等到自己练熟了以后我专门写一篇 我今天只写社交网络相关, 希望被我无耻强推连接的好友在评论里面多提意见,我也多改进。
场景 Scenario
上来我们第一个问题,没啥说的,
用户在twitter/facebook/weibo上面都干啥?
社交网络是吧,定义一下,是每个用户(人)对社交群体(人)的信息(帖子)分享。
人和帖子,俩基本点,所以说呢?
1. 好友关系,加好友,删好友, (改好友),查好友
2. 帖子关系,加帖子,删帖子,改帖子,查(谁的)帖子
具体点呢?
增删帖子
timeline (所有好友/单个好友的最近N个帖子。为啥N个?一屏放不下,数据发不完)
新闻(理解成厂家小编名义发送的帖子,是为新闻 news feed)
好友管理(增删改查,想到什么了没)
用户管理(登陆、注册、profile)
第二个问题,也没啥说的,
我需要考虑多大的数据量?
《=多大用户量以及用户都怎么用的?
具体下来是这么几个:
1. 日活用户多少啊?(How many daily active user(DAU) should I expect)
根据不完全调查,一般来说:
twitter: DAU 10M
facebook: DAU 1.2B
weibo: MAU 340M, DAU 11M
2. 每天每个用户要expect多少个新帖子啊,多少次阅读啊?(How many daily new posts/reads should I expect per user)
大坑预警: 不是直接问总共多少个,咱不是产品经理,问每人多少个
twitter/facebook/weibo: 20min *25 read/min = 500 reads per user per day. (亲测差不多) 5 writes per user per day(亲测比这个少,但是自己跟朋友平均下来,这个数字也靠谱)
3. 知道这几个数字了,能算QPS了不?
大坑预警:QPS的S是啥?DAU的D是啥?两者啥关系?
一天多少秒?24*60*60 = 86400秒
就先拿weibo来算好了,中国人关注中国企业
Read QPS: 500 * 11,000,000/ 86,400 .= 70K
Write QPS: 5 *11,000,000/86,400 = 700 QPS
啥概念?咱一会儿说 别忘了哈!
实现 Implementation
来 先画图
我的架子怎么搭?
关键点是? 人和帖子?
人需要几个service? 好友管理和用户登陆
帖子需要几个service?帖子管理和大文件存储
所以一共?四个service
User service
每个用户的基本资料
注册 登陆
Posting Service
每个帖子的内容和资料
大坑预警:可别在这里放图片/文件/视频哈,说挂立刻就挂!! 那要放放哪?attachment service 能让别人打架绝不自己动手:)
Friendship Service
放每个用户的好友关系
facebook 你是我好友 我肯定是你好友 双向保存也可以,单向保存也可以
twitter/weibo不一定哦 分关注和被关注,这里到底是保存关注,保存被关注,还是都需要保存,就看具体实现了,设计的时候要有意识
Attachment service 统一存放所有的大文件(图片,视频,pdf 等)
如果多个人有同一个文件 正好!
下一个问题:
数据怎么放?
首先 基本概念,每个service考虑自己的就行。
为啥?做成SOA(Service Oriented Architecture) 不就是为了每个service可以自己做事情么 而且每个service的数据存储模式是不一样的。既然不一样,那就分开放。
下一个问题: 那你倒是放呀?
好好 不着急不着急。。。
User Info: 读远大于写,经典的SQL应用。
Post Info: 内容不定,读写频繁,除时间外无法排序,适合NoSQL
Attachment Info: 大文件 这就没啥可说的,只能放在文件系统里面。
Friendship info: 关系确定(好友呗,最多再分一个类),有时排序,读远大于写。这个就不好说了。你想存SQL也行,你想存NoSQL也行。
关于这几个数据库之间的关系,什么时候该用哪一个。我就将来另写一篇文章说这个问题了。感觉谁都会用到的。
下一个问题: 该有的有了 该存的存了,
流程啥样?
用户注册:没啥可说的,user table里加一个entry
用户注销: 别愣着直接删,标记不活跃就可以了
用户登陆:关键字,不要原样传输密码,不要原样储存密码
发帖:发帖。。。
讲究就大了
单纯发帖好说,post table里面加一个entry。如果有大文件,entry里面自动添加链接,attachment table里面加一个节点或者重用已有文件。
可是我要怎么让关注我的人(不管是单向的还是双向的知道我发帖了呢)?
首先 要想到有两种做法(想到一种不是你的错,但是认为没有别的路就是你要准备好被挂了)
1. Push model: 用户发帖以后更新自己的记录以外,遍历所有follow自己的人,把这条帖子推送给他们对应的user service。user service 保存推送来的消息,用户显示朋友圈的时候,在接收到的消息里面选取topK个显示。
2. Pull model: 用户发帖以后更新自己的记录。用户显示朋友圈的时候,把遍历所有自己follow的人拿topN个显示(N和K的关系可以另外算),截取topK个显示。
所有培训机构的图都是有版权的不能用。我给大家放一个不完全准确的图。简单说,这里面都有一个遍历关系。
push:遍历所有follow自己的人,每个人推送自己的更新
pull:遍历所有自己follow的人,每次显示朋友圈的时候询问更新
那我要怎么选择呢?上课都会讲怎么选择的,我们先从各自的优缺点开始。
push:如果follow自己的人不多,省!
pull:如果自己follow的人不多,省!
push:如果自己follow的人不都活跃,省!
pull:如果follow自己的人不都活跃,省!
push:会带来一个特定的问题,叫做惊群效应 就是如果今天王宝强发了一个帖子,我的天爷,大家是不是纷纷点赞纷纷转发纷纷评论,这个如果用push的话,fanout结束怎么也得好几个小时吧?
这个问题为啥难,因为所有的人修改的都是同一个帖子。什么caching,sharding,根本都不管用。我贴的链接不是关于网络系统设计的,是关于计算机系统设计的。这个问题不分软件固件,大家都能碰到。解决的办法说起来也只有慢慢fanout了,只要在用户的视角里面显示自己评论就可以了。
pull:这个问题就不是特定了,为啥,因为王宝强少,看王宝强的人多。不论已婚与否,我们今天基本上男性劳苦大众都是关注的人比被关注的多。所以我们的问题就现打不赊着,如果不做任何优化,我们每次更新都要很慢,因为每次看朋友圈都要二重循环
以上是基本解的实现。说了这么多,我想我都累了。面试官应该不会挂了吧(有问题指出来,要不我还是得挂!)。接下来就要说说一些相对比较高级的功能了。
提高 Enhancement
我自己这个破记性 能够把基本点记下来就不容易了,接下来你说要提高,那我们从提高开始,要记住什么要点呢?
就从奥林匹克精神开始吧。更高咱先不说,先说后面两个
更快:前面分析完了并发性 现在可以开始说说速度了,怎么样更快得到结果,让前端尽可能的不要等?
更强:就是面对可能出现的各种问题是否有更好的准备和更好的解决办法。
接下来我们就一个一个说我这里可能会想到的问题。
我们先说更快,因为基本解来说,更快还是相对比较容易做到的。
我们之前在基本解说了这么多,我们自己每天也都在用社交网络,我们要优化东西,就要牺牲东西。可以牺牲的东西一定是我们不太看重,或者不太感觉得到的东西,对吧?那么我们什么可以牺牲?什么不那么重要?
答案:实时性(Real-time-ness)
为啥?你今天分析你一个交恶的原密友发的不利于你的消息。你就关心他消息是什么时候发出来的,对不对?什么时候到你这里的,只要别太慢,你自己也没感觉,对吧?
所以,只要保证时序性(最先发出来的帖子,最后在用户这里显示是显示在前面的),可以允许有些消息先显示出来,然后等到别人的消息来了再整理就好了。
这样,对于pull来说,就有一个特别好的消息了。 我可以用缓存了。
我先把缓存里面的信息先放出来,然后有消息来了我一点一点加进去(大家用微信看消息是不是就是这个感觉?消息在一点一点的更新?这就是pull+cache的用户体验)
那push呢?
王宝强级别的明星必须用pull,没说的。否则没有别的任何招数。普通人可以用push,反正不伤。
那是吧,我们结合一下,如果明星用pull,普通人用push,是不是就两全其美了呢?
不能说不是,但是会带来新的问题。叫摇摆效应。啥叫摇摆效应?
比如说吧,咱划个线,粉丝一万以上叫明星,一万以下叫普通人
要是有人本来10001个粉丝,今天掉了两个粉,我怎么办?如果明天又涨回来两个粉,我又怎么办?
后台可以在这俩之间切来切去,但是这样不是要反复通知上下游的其他service吗?
解决这个问题的办法来说,比较容易想到的就是设置一个过渡期,先默认是明星,如果普通人变成了明星,立刻改,如果明星变成了普通人,等待一段时间。
下一个问题,取关怎么处理?
还是那句话,你取关谁你看不见就行!
所以我们就可以异步操作,先立刻删除缓存,在本机禁止显示关于被取关好友的消息,然后再异步发送给服务器来删除服务器上的好友记录。
下一个话题, 更强, 也就是不能有东西挂掉
单点failure怎么办?(有一台数据中心或者服务器down了)
一,数据要复制,一份数据不能只放在一个地方(replica)
二,数据要分散,不能所有的数据只放在一个地方(sharding)
如何识别虚假用户?
一,用户举报机制
二,这是一个典型的supervised learning/classification, 用machine learning辅助判断
然后今天就先说道这里。就像开头说的,系统设计想挂人还不容易,稍微在他进行的时候打断他两下问他两个细节,很多人就都不行了。所以。一定要记住大框架,然后时刻记住自己说道哪里了。