可行解 Work Solution | 15% |
特定问题 Special Case | 20% |
分析能力 Analysis | 25% |
权衡 Trade-off | 15% |
知识储备 Knowledge | 25% |
哪些功能?Feature/Interface?算法
多强的系统?Constrains/Hypothesis/QPS/DAU数据库
主要组成模块?Service/Module数据结构
如何存储数据和访问?Data/Storage/SQL vs. NoSQL/File System/Schema并发
如何进化,解决缺陷,处理问题?Optimize/Special Caseless
Register/Login异步
User Profile Display/Editide
Upload Image/Videomemcached
Searchpost
Post/Share a tweet优化
Timeline/News Feed
Follow/Unfollow a user
Post a tweet
Timeline
News Feed
Follow/Unfollow
Register/Login
DAU -- Daily Active Users -- 日活跃用户数量 -- 评价系统牛逼的标准
Twitter: MAU 320M, DAU ~150M+
Read More: http://bit.ly/1Knl0M7
Concurrent Users -- 并发用户
Avg Concurrent Users = 日活跃用户数量 * 每一个用户平均请求次数 / 一天多少秒
= 150M * 60 / 86400 ~= 100k
峰值:Peak Users = Avg Concurrent Users * 3
~ 300k
快速增加的产品:Fast Growing = Peak Users * 2
~ 600k
Read QPS(Queries Per Second) 读频率:300k
Write QPS(Queries Per Second) 写频率:5k
Receptionist
User Service: Register/Login
Tweet Service: Post a tweet/News Feed/Timeline
Media Service: Upload Picture/Video
Friendship Service: Follow/Unfollow
关系型数据库 SQL Database:User Table
非关系型数据库 NoSQL Database:Tweets, Social Graph (Followers)
文件系统 File System: Images, Videos, other media files
程序 = 算法 + 数据结构
系统 = 服务 + 数据存储
User Service: SQL
Tweet Service: NoSQL
Media Service: File System
Friendship Service: SQL/NoSQL
为每一个App/Service选择合适的存储结构
细化Database结构
User Table | |
---|---|
userId | integer |
username | varchar |
varchar | |
password | varchar |
Friendship Table | |
---|---|
relationshipId | integer |
from_userId | foreign key |
to_userId | foreign key |
Tweet Table | |
---|---|
tweetId | integer |
userId | foreign key |
time | timestamp |
content | text |
Pull Model
获取每一个好友的前k条tweets,合并出k条news feed
K路归并算法:Merge K sorted arrays
假设有N个好友,则时间为 ==>
N次DB Read的时间 + K路归并时间(可忽略)
Post a tweet ==>
1次DB Write的时间
Client ---->send get News Feed
request to----> Server
Server <----get Following
from----> Friendship Table
Server <----get Tweets
of Followings
from----> Tweet Table
Server ---->Merge Tweets
and return to----> Client
读取慢(N次DB Reads,很是慢)
发生在用户得到News Feed的请求过程当中,有延迟
为每一个用户建一个List存储他的News Feed;
当他post一个tweet的时候,将该推文逐个推送(Fanout)到每一个Follower的List中;
当他查看News Feed时,从List中读取最新的100条便可
每次News Feed,只用一次DB Read;
每次Post Tweet,会Fanout到N个Follower,须要N次DB Writes;
不过对于Post Tweet,能够用异步任务后台执行,用户无须等待
postTweet(POST, tweet_info) { tweet = DB.insertTweet(userId, tweet_info); //userId对应这个用户的News Feed List AsyncService.fanoutTweet(userId, tweet); return success; } AsyncService::fanoutTweet(userId, tweet) { followers = DB.getFollowers(userId); for (follower: followers) { DB.insertNewsFeed(follower.userId, tweet); } }
postTweet()的异步执行;而fanoutTweet()可能遇到followers数目太大的问题。
Pull | |
Pull | |
Pull + Push |
Solve Problems: Push vs. Pull; Normalize vs. De-normalize
More Features: Edit; Delete; Media; Ads
Special Cases: 大V,热推,不活跃用户
Robust 鲁棒性:若是有一台server/DB挂了怎么处理
Scalability 扩展性:若是有流量暴增,如何扩展
在访问DB以前加入Cache;
Cache每一个用户的Timeline
N次DB Reads,因此Cache最近的100条
Cache每一个用户的News Feed
最近没有Cache过News Feed的用户:归并N个好友每人最近的100条Tweets,取出前100条;
最近Cache过的用户:归并某个时间戳以后的tweets
浪费更多Disk存储空间
与Pull模型存在Memory中相比,虽然Disk很便宜
其实对于实时性要求而言,Push的效果不如Pull
因此对于不活跃用户,能够采用粉丝排序
follower数目远大于following数目时,加几台push任务的机器
若是加server没法解决:针对长期的fast growing,进行评估,转换push模型为pull模型
Tradeoff:对于明星用户,采用pull;对于普通用户,采用push(朋友圈);
Follow以后:异步将他的Timeline合并到你的News Feed中
Unfollow以后:异步将他的Tweets从你的News Feed中移除
异步的好处:用户迅速获得反馈,觉得succeess了,无须等待异步操做的真正完成
异步的坏处:若是unfollow以后刷新,发现他的Tweets还在
标准化操做:Normalize:两个tables,使用Join操做,时间更多
因此,使用去标准化操做:De-normalize
对于同一条数据短期出现大量请求:
load balancer, sharing, consistent hashing都不是颇有效;
加入cache能够完美解决;
Follow Up 1:
Like, Retweet, Comment都会改变该tweet的基本信息,如何更新?
Write through; Write back; Look aside
Follow Up 2:
Cache失效怎么办,例如内存不够或者Cache决策失误,致使tweet
Answer: http://www.cs.utah.edu/~stuts...
While building, maintaining, and evolving our system we have learned the following lessons. (1) Separating cache and persistent storage sys- tems allows us to independently scale them. (2) Features that improve monitoring, debugging and operational ef- ficiency are as important as performance. (3) Managing stateful components is operationally more complex than stateless ones. As a result keeping logic in a stateless client helps iterate on features and minimize disruption. (4) The system must support gradual rollout and roll- back of new features even if it leads to temporary het- erogeneity of feature sets. (5) Simplicity is vital.
Please refer to next article.