分享优秀网友的文章,好文
下面以:设计Twitter为例子,用4s分析法来解剖Twitter
Scenario 场景
Scenario 场景 需要设计哪些功能,设计得多牛
- Ask 问面试官
- Analysis 分析 Scenario 场景 - Ask 多问,切记
询问面试官:
- • 需要设计哪些功能(也可以自己想)
- • 需要承受多大的访问量?
- • 日活跃用户 Daily Active Users (DAU) •
假设我们要设计一个Twitter。 (** 系统)
Twitter: MAU 330M, DAU ~170M+ • MAU - Monthly Active Users 衡量网站用户数的重要指标-。一般不是用注册用户,而是用月活跃用户来代表一个网站的用户数
Scenario 场景 – 需要设计哪些功能
• 第一步 Step 1:Enumerate 第一步:罗列功能
- • 说人话:把Twitter的功能一个个罗列出来
- • Register / Login
- • User Profile Display / Edit
- • Upload Image / Video *
- • Search *
- • Post / Share a tweet
- • Timeline / News Feed
- • Follow / Unfollow a user
• 第二步 Step 2:Sort 第二步:筛选
- • 说人话:选出核心功能,因为你不可能这么短的时间什么都设计
- • Post a Tweet
- • Timeline
- • News Feed
- • Follow / Unfollow a user
- • Register / Login
– Analysis & Predict(预测)
并发用户 Concurrent User • 日活跃 * 每个用户平均请求次数 / 一天多少秒 = 150M * 60 / 86400~ 100k 猜测
- • 峰值 Peak = Average Concurrent User * 3 ~ 300k
- • 快速增长的产品 Fast Growing • MAX peak users in 3 months = Peak users * 2
- • 读频率 Read QPS (Queries Per Second) • 300k
- • 写频率 Write QPS • 5k
注意顶:重要的不是计算过程 而不是计算结果
分析出 QPS 有什么用?
- • QPS = 100 • 用你的笔记本做 Web 服务器就好了
- • QPS = 1k • 用一台好点的 Web 服务器就差不多了
- • 需要考虑 Single Point Failure
- • QPS = 1m
- • 需要建设一个1000台 Web 服务器的集群
- • 需要考虑如何 Maintainance(某一台挂了怎么办)
分析出 QPS 有什么用?
- • QPS和 Web Server (服务器) / Database (数据库) 之间的关系
- • 一台 Web Server 约承受量是 1k 的 QPS (考虑到逻辑处理时间以及数据库查询的瓶颈)
- • 一台 SQL Database 约承受量是 1k 的 QPS(如果 JOIN 和 INDEX query比较多的话,这个值会更小)
- • 一台 NoSQL Database (Cassandra) 约承受量是 10k 的 QPS • 一台 NoSQL Database (Memcached) 约承受量是 1M 的 QPS
Service 服务
将大系统拆分为小服务 可以理解为:拆分模块,业务模块,还没到拆分微服务的时候
- Replay 重放需求
- Merge 归并需求
Service 服务 – 将大系统拆分为小服务
• 第一步 Step 1: Replay • 重新过一遍每个需求,为每个需求添加一个服务
• 第二步 Step 2: Merge • 归并相同的服务
- 3. • 什么是服务 Service?
-
- • 可以认为是逻辑处理的整合
-
- • 对于同一类问题的逻辑处理归并在一个 Service 中
-
- • 把整个 System 细分为若干个小的 Service
Storage 存储
数据如何存储与访问
- Select 为每个 Service 选择存储结构
- Schema 细化表结构
Storage 存储 – 数据如何存储与访问
- • 数据库系统 Database • 关系型数据库 SQL Database • 用户信息 User Table • 非关系型数据库 NoSQL Database • 推文 Tweets • 社交图谱 Social Graph (followers)
- • 文件系统 File System • 图片、视频 Media Files
- • 缓存系统 Cache
- • 不支持数据持久化 Nonpersistent • 效率高,内存级访问速度
Storage 存储 – 数据如何存储与访问
• 第一步 Step 1: Select • 为每个 Application / Service 选择合适的存储结构 • 第二步 Step 2: Schema • 细化数据表结构
• 程序 = 算法 + 数据结构 • 系统 = 服务 + 数据存储
Interviewer: Please design schema
新鲜事系统 News Feed • 什么是新鲜事 News Feed? • 你登陆 Facebook / Twitter / 朋友圈 之后看到的信息流 • 你的所有朋友发的信息的集合 • 有哪些典型的新鲜事系统? • Facebook • Twitter • 朋友圈 • RSS Reader • 新鲜事系统的核心因素? • 关注与被关注 • 每个人看到的新鲜事都是不同的
Storage 存储 – Pull(拉) Model • 算法• 在用户查看News Feed时,获取每个好友的前100条Tweets,合并出前100条News Feed • K路归并算法 Merge K Sorted Arrays
• 复杂度分析 • News Feed => 假如有N个关注对象,则为N次DB Reads的时间 + N路归并时间(可忽略) • Post a tweet => 1次DB Write的时间
为什么 N 路归并算法 的耗时可以忽略?
Storage 存储 – Pull 原理图 用户
- Give me News Feed
- Merge and return
Web Server 2. Get followings 3. Get tweets from followings
Interviewer: Pull模型有什么缺陷么?
Storage 存储 – Pull Model
- • getNewsFeed(request)
- • followings = DB.getFollowings(user=request.user)
- • news_feed = empty
- • for follow in followings:
- • tweets = DB.getTweets(follow.to_user, 100)
- • news_feed.merge(tweets)
- • sort(news_feed)
- • return news_feed[:100] # 返回前100条
N次DB Reads非常慢 且发生在用户获得News Feed的请求过程中
• postTweet(request, tweet) • DB.insertTweet(request.user, tweet) • return success
Storage 存储 – Push(推) Model
- • 算法
- • 为每个用户建一个List存储他的News Feed信息
- • 用户发一个Tweet之后,将该推文逐个推送到每个用户的News Feed List中
- • 关键词:Fanout • 用户需要查看News Feed时,只需要从该News Feed List中读取最新的100条即可
• 复杂度分析 • News Feed => 1次DB Read • Post a tweet => N个粉丝,需要N次DB Writes • 好处是可以用异步任务在后台执行,无需用户等待
Interviewer: Push模型有缺陷么?
-
• getNewsFeed(request)
-
• return DB.getNewsFeed(request.user)
-
• postTweet(request, tweet_info)
-
• tweet = DB.insertTweet(request.user, tweet_info)
-
• AsyncService.fanoutTweet(request.user, tweet) -- 异步执行
-
• return success
-
• AsyncService::fanoutTweet(user, tweet)
-
• followers = DB.getFollowers(user)
-
• for follower in followers:
-
• DB.insertNewsFeed(tweet, follower) -- followers的数 目可能很大
Pull vs Push 解析
pull模式 :客户端主动从服务端拉取消息。 优点:客户端不存在消息堆积的情况。 缺点:消息处理不及时,可能存在大量无效请求,客户端需要考虑拉取频率逻辑
Pull:当服务端收到这条消息后什么也不做,只是等着Consumer 主动到自己这里来读,即 Consumer 这里有一个“拉取”的动作(即为你来我就服务)。
push模式 :服务端主动给客户端推消息的。 优点:消息及时到达。 缺点:无法感知客户端的消费能力,可能造成客户端消息堆积
Push:当Producer 发出的消息到达后,服务端马上将这条消息投递给 Consumer。
Storage 存储 – Pull vs Push
• 热门Social App的模型 • Facebook – Pull • Instagram – Push + Pull • Twitter – Pull • 朋友圈 - ?
• 误区 • 不坚定想法,摇摆不定 • 不能表现出Tradeoff的能力 • 无法解决特定的问题
• 前3个步骤的分析,我们已经得到了一个可行方案
• Scenario 场景 和面试官讨论 搞清楚需要设计哪些功能 并分析出所设计的系统大概所需要支持的 Concurrent Users / QPS / Memory / Storage 等
• Service 服务 • 合并需要设计功能,相似的功能整合为一个Service
• Storage 存储 • 对每个 Service 选择合适的存储结构 • 细化数据表单 • 画图展示数据存储和读取的流程
• 得到一个 Work Solution 而不是 Perfect Solution • 这个Work Solution 可以存在很多待解决的缺陷
Scale 扩展 How to Scale?
系统如何优化与维护 1. Optimize 优化 2. Maintenance 维护
Scale 扩展 - 如何优化系统
第一步 Step 1: Optimize
- • 解决设计缺陷 Solve Problems
- • Pull vs Push
- • 更多功能设计 More Features
- • Like, Follow & Unfollow, Ads
- • 一些特殊情况 Special Cases
- • 鹿晗关晓彤搞挂微博, 僵尸粉
第二步 Step 2: Maintenance
- • 鲁棒性 Robust • 如果有一台服务器/数据库挂了怎么办
- • 扩展性 Scalability • 如果有流量暴增,如何扩展
Scale 扩展 – 解决Pull的缺陷
• 最慢的部分发生在用户读请求时(需要耗费用户等待时间) • 在 DB 访问之前加入Cache • Cache 每个用户的 Timeline • N次DB请求 → N次Cache请求 (N是你关注的好友个数)
• Trade off: Cache所有的?Cache最近的1000条? • Cache 每个用户的 News Feed • 没有Cache News Feed的用户:归并N个用户最近的100条Tweets,然后取出结果的前100条 • 有Cache News Feed的用户༚ 归并N个用户的在某个时间戳之后的所有Tweets
• 思考题:对比MySQL 和 Memcached 的 QPS
• Memcached QPS / MySQL QPS ~ 100 ~ 1000
Scale 扩展 – 解决Push的缺陷
- • 浪费更多的存储空间 Disk
- • 与Pull模型将News Feed存在内存(Memory)中相比
- • Push模型将News Feed存在硬盘(Disk)里完全不是个事儿
- • Disk is cheap
- • 不活跃用户 Inactive Users
- • 粉丝排序 Rank followers by weight (for example, last login time)
- • 粉丝数目 followers >> 关注数目 following
- • Lady Gaga问题 无解?完全切换回Pull?
- • Trade off: Pull + Push vs Pull
粉丝 Followers 80 M • Justin Bieber 95 M on Instagram • 谢娜 100M on Weibo
• Push 的挑战
• Fanout 的过程可能需要几个小时!
• 错误的回答方案
- • 既然 Push 不行,那我们就切换到Pull 吧!--大忌,临时换方案,技术的大忌。会被对方质疑能力
- • 说起来好容易啊!
Scale 扩展 – Lady Gaga
正确的思路
- • 尝试在现有的模型下做最小的改动来优化
- • 比如多加几台用于做 Push 任务的机器,Problem Solved!
- • 对长期的增长进行估计,并评估是否值得转换整个模型
Push 结合 Pull 的优化方案 -- 改进,根据明星,采纳不同的方法
- • 普通的用户仍然 Push
- • 将 Lady Gaga 这类的用户,标记为明星用户
- • 对于明星用户,不 Push 到用户的 News Feed 中
- • 当用户需要的时候,来明星用户的 Timeline 里取,并合并到 News Feed 里
如何定义明星?
单纯的用followers > 1m 是否有问题?
实时计算的话:会有个临界值
是不是明星不能在线动态计算,要离线计算 • 为 User 增加一个 is_superstar 的属性 • 一个用户被标记为 superstar 之后,就不能再被取消标记
- • 为什么既然大家都用Pull,我们仍然要学习Push?
- • 系统设计不是选择一个最好的方案
- • 而是选择一个最合适的方案
- • 如果你没有很大的流量,Push是最经济最省力的做法
- • 系统设计也并不是期望你答出最优的解决方法,而是从你的分析当中判断你对系统的理解和知识储备。
Scale 扩展 – Pull vs Push
什么时候用 Push?
- 2. • 资源少
-
- • 想偷懒,少写代码
-
- • 实时性要求不高
-
- • 用户发帖比较少
-
- • 双向好友关系,没有明星问题(比如朋友圈)
什么时候用 Pull ?(实时)
- 2. • 资源充足
-
- • 实时性要求高
-
- • 用户发帖很多
-
- • 单向好友关系,有明星问题
Ask before design
问清楚再动手设计 不要一上来就冲着一个巨牛的方案去设计 切忌不要做关键词大师
Work solution first 先设计一个基本能工作的系统,然后再逐步优化 Done is better than perfect! —— Mark Zuckerberg
Analysis is important thansolution 系统设计没有标准答案 记住答案是没用的 通过分析过程展示知识储备 权衡各种设计方式的利弊
果断取关问题?
• 如何实现 follow 与 unfollow? • Follow 一个用户之后,异步地将他的 Timeline 合并到你的 News Feed 中 • Merge timeline into news feed asynchronously. • Unfollow 一个用户之后,异步地将他发的 Tweets 从你的 News Feed 中移除 • Pick out tweets from news feed asynchronously.
• 为什么需要异步 Async? • 因为这个过程一点都不快呀(耗时)
异步的好处? • 用户迅速得到反馈,似乎马上就 follow / unfollow 成功了 • 异步的坏处? • Unfollow 之后刷新 News Feed,发现好像他的信息还在 • 不过最终还是会被删掉的
拓展问题2:如何存储 likes? 如何在 News Feed 中 同时得到每个帖子被点赞、评论和转发的次数?
文件系统和数据库系统的关系是什么?(补充)
数据库系统 vs 文件系统 关系:数据库系统是文件系统的一层包装,他们不是独立的关系,是依赖的关系。数据库系统依赖于文件系统。
区别:数据库系统提供了更丰富的数据操作,很细;文件系统只提供了简单的文件操作接口,很粗。 以关系型数据库(Relational Database) 为例,提供了 SQL 语句这样的丰富的查询语言,可以一些复 杂的 filter,如快速找出学生信息表中,所有 20-24 岁的学生信息。 如果直接在文件系统上,则需要 扫描完所有的学生数据后才能找到。 数据库系统中读取的数据,大部分情况下(除了被 cache 的),都还是会到文件系统上去读取出来的。 因此两个系统的读写效率(不考虑复杂查询)可以认为是差不多的。