系统设计的评分标准
- 可行性
- 特定问题
- 分析能力
- 权衡
- 知识储备
系统设计问题4S分析法
Scenario 场景
- 需要设计哪些功能,设计的多牛
- Ask / Features / QPS / DAU / Interfaces
Service 服务
- 将大系统拆分为小服务
- Split / Application / Module
Storage 存储
- 数据如何存储与访问
- Schema / Data / SQL / NoSQL / File System
Scale 升级
- 解决缺陷,处理可能遇到的问题
- Sharding / Optimize / Special Case
Scenario 场景
ASK
-
需要设计哪些功能?
-
需要承受多大的访问量? DAU MAU
- 问这个是需要计算QPS
需要设计哪些功能
-
第一步 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和 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 服务
将大系统拆分为小服务
-
第一步 Step 1: Replay
- 重新过一遍每个需求,为每个需求添加一个服务
-
第二步 Step 2: Merge
- 归并相同的服务
-
什么是服务 Service?
- 可以认为是逻辑处理的整合
- 对于同一类问题的逻辑处理归并在一个 Service 中
- 把整个 System 细分为若干个小的 Service
Storage 存储
数据如何存储与访问
-
关系型数据库 SQL Database
- 小调查:Twitter的哪些信息适合放在关系型数据库中?
- 用户信息 User Table
-
非关系型数据库 NoSQL Database
- 小调查:Twitter的哪些信息适合放在非关系型数据库中?
- 推文 Tweets
- 社交图谱 Social Graph (followers)
-
文件系统 File System
- 小调查:Twitter的哪些信息适合放在文件系统中?
- 图片、视频 Media Files
步骤:
-
第一步 Step 1: Select
- 为每个 Application / Service 选择合适的存储结构
-
第二步 Step 2: Schema
- 细化数据表结构
程序 = 算法 + 数据结构
系统 = 服务 + 数据存储
Interviewer: Please design schema
Interviewer: News Feed 如何存取?
什么是新鲜事 News Feed?
- 你登陆 Facebook / Twitter / 朋友圈 之后看到的信息流
- 你的所有朋友发的信息的集合
Pull Model
-
算法
- 在用户查看News Feed时,获取每个好友的前100条Tweets,合并出前100条News Feed
- K路归并算法 Merge K Sorted Arrays
-
复杂度分析
-
News Feed => 假如有N个关注对象,则为N次 DB Reads的时间(读DB非常耗费性能的) + K路归并时间(可忽略)
- 为什么K路归并的时间可以忽略?
-
Post a tweet => 1次DB Write的时间
-
Interviewer: Pull模型有什么缺陷么?
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
- 好处是可以用异步任务在后台执行,无需用户等待
-
-
News Feed Table
Interviewer: Push模型有缺陷么?
Scale 扩展
如何优化系统
-
第一步 Step 1: Optimize
-
解决设计缺陷 Solve Problems
- Pull vs Push, Normalize vs De-normalize
-
更多功能设计 More Features
- Edit, Delete, Media, Ads
-
一些特殊用例 Special Cases
- Lady Gaga, Inactive Users
-
-
第二步 Step 2: Maintenance
-
鲁棒性 Robust
- 如果有一台服务器/数据库挂了怎么办
-
扩展性 Scalability
- 如果有流量暴增,如何扩展
-
解决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
-
解决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
-
Lady Gaga
-
粉丝 Followers 65.5M
- Justin Bieber 80M on Instagram
- 谢娜 90M on Weibo
- 以上数据来自2017年3月
-
Push 的挑战
- Fanout 的过程可能需要几个小时!
-
面试时错误的回答方案
- 既然 Push 不行,那我们就切换到 Pull 吧!
-
正确的思路
-
尝试在现有的模型下做最小的改动来优化
- 比如多加几台用于做 Push 任务的机器,Problem Solved!
-
对长期的增长进行估计,并评估是否值得转换整个模型
-
Push 结合 Pull 的优化方案
- 普通的用户仍然 Push
- 将 Lady Gaga 这类的用户,标记为明星用户
- 对于明星用户,不 Push 到用户的 News Feed 中
- 当用户需要的时候,来明星用户的 Timeline 里取,并合并到 News Feed 里
摇摆问题
-
明星定义
- followers > 1m
-
邓超掉粉
- 邓超某天不停的发帖刷屏,于是大家果取关,一天掉了几十万粉
-
解决方法
-
明星用户发 Tweet 之后,依然继续 Push 他们的 Tweet 到所有用户的 News Feed 里
- 原来的代码完全不用改了
-
将关注对象中的明星用户的 Timeline 与自己的 News Feed 进行合并后展示
- 但并不存储进自己的 News Feed 列表,因为 Push 会来负责这个事情。
-
Pull vs Push
取关问题