题目
用户可以上传照片,分享照片;关注其他人,亦可以看到自己的和好友的top照片;
Use Cases
功能性
- 支持用户上传/下载/查看 照片
- 根据名称搜索照片
- 用户关注他人
- 生成和展示信息流,包含所有关注的人的top照片
非功能性
5. 高可用
6. 低时延:信息流产生时延 < 200ms
7. AP系统:保可用性,特殊情况用户一段时间看不到照片也是OK的
8. 高可靠,上传的照片不能丢失
out of scope
- 为照片添加tag,根据tag搜索,评论,查看粉丝
约束
- ***首先和面试官声明该系统的几个设计关键点
- 用户会上传大量照片,存储系统的管理是关键
- 查看照片需要低时延
- 数据100%不丢失***
- read/write 100:1 DAU:1M
- 每天1M新照片,QPS:10
- 500M用户,日活1M
- 一个照片10M,10TB/Day,300TB/month,18PB/5 years
- 元数据:一条记录 = title(1KB) + created_at(10B) + details(4KB); 一个月30M * 5KB = 150GB(不太准确,需要在schema设计后计算)
High Level
- client upload/download/search/view service + core image service + image storage service + meta data service
DB Design
-
数量多10B 条记录
-
单条记录小 5KB
-
表关联不是很强,用户表 + 图片信息表 + 用户关系表
-
读多,前缀搜索/后缀搜索:根据名称搜索
-
没有事务性要求,扩展性要求高,选择NOSQL
- key=image_id value=object(name, title, size,…)
-
照片可以存储在分布式文件存储,HDFS / S3
-
a wide-column datastore可以存储list作为value,适合保存一个user拥有的imageId,一个user拥有的followers
DB schema
- table:image_info + user + user_relation
image_info:table
PK:image_id:varchar(32) int
name image_path :varchar(256)
title:varchar(2048)
size:int
user_id:int
created_at:datetime
update_at:datetime
is_delete:int (NOSQL延迟删除,所以不需要该字段)
user:table
PK:user_id:int
name:varchar(256 20)
created_at:datetime
last_login:datetime
user_relation:table
PK:from_id + to_id
from_id: int
to_id: int
is_follow:int
created_at:datetime
update_at: datetime
message:table
PK: message_id:int
user_id:int
image_id:int
title:varchar(2048)
created_at:datetime
top_message:table
PK:user_id:int
update_at:datetime
top_message:text
容量预估
- User:int和datetime都是4B,4 + 20 + 4 + 4 = 32 B;500M * 32 B ~= 16 G
- image:4 + 256 + 4 + 4 + 4 = 272 B;1M * 272 B = 0.27 G per day
- userFollow:500M * 500 followers * 12B = 3 TB
详细设计
读写服务分离
- 背景:写过程较慢,web server连接数有上限,会阻塞读请求;读写分离也便于分开优化和扩容;
- upload服务,请求量较低QPS 10,写image storage service(S3)和metadata服务
- download服务,先读CDN,miss后再读metadata服务,再读S3服务
- 查看服务,QPS 10000,先读浏览器cache,再读CDN,再读metadata服务,再读S3服务
- 搜索服务,读cache,然后再从metadata服务,获取搜索结果
扩展
可靠性
- storage服务,3副本
- metadata 主从架构
- download和upload service也是多个实例在跑
高并发
- 核心服务前LB,rr策略
- 读请求增加过期cache
- 用户来自世界各地,需要将内容push到离用户更近的cache服务器,例如使用CDN
- 为metadata服务增加cache服务,缓存热点的数据库rows,memcache;淘汰策略LRU
- 问题:如何更高效地缓存;缓存20%的真实数据和元数据
扩展性
- 存储服务数据sharing,根据image_id来哈希到不同的存储节点;讨论两种sharding的方案
- 1.根据user_id,一个user的photo都保存在一个shard中,一个shard=1TB,假定一共10个shard,每次查找时user_id % 10找到shard;
- 1.问题:1)热点user 2)user数据过大 3)用户数据量不同,存储分布不均匀 4)用户所有数据都不可用(某个shard down)和高时延(某个shard负载高)
- 2.根据image id,先生成image id,然后image id % 10 ,分布会均匀;每次上传image,都索引到shard,然后写数据;读取时也是根据imag id做索引;解决了1)2)3)4)问题
-
- 问题:1)热点image 2)如何扩展?
- 3 答案:1)加缓存??? 2)维护单独的config服务,维护logic partion和physical 数据库服务的map;如果一个数据库满时,我们可以移动一些partition到其他数据库服务。
信息流设计
- push:每次发布,都将消息推送到所有的set<from_id>,对于每一个from_id 将消息id添加到队首,如果队列消息超过10个,淘汰掉最旧的消息;
- 问题:明星人物push有性能问题;写入数据过多;
- pull: 获取用户信息流时,主动拉取set<to_id>的消息,然后根据时间排序,选取最新的前10个照片;
- 问题:如果关注的人过多,时延可能超过200ms;
- 混合模式:明星人物不push,其他人物均push;