文章目录
需求边界
全世界用户分享照片视频
权限:公开,私人
关注其他用户
全局热门消息照片
-
功能要求
- 上传、下载查看照片
- 搜索功能
- 关注其他用户
- 热门照片
-
非功能
- 服务高可用
- 高可靠,消息不丢失
- 消息延迟低
接口定义
容量估计
假设
- 系统年限 10年
- 总用户5亿,活跃用户100万,每个用户关注500个
- 平均每人每天2张照片,每天200万照片,每秒23张
- 每张照片 200kb
每天容量 = 2M * 200KB => 400 GB
10年 = 400GB * 365 * 10(年)~= 1425TB
数据模型
数据库服务sql或nosql 存储:
用户表(userId,name,email,DateOfBirth。。。)
照片表(photoId,位置,user,CreationDate)
关注表(用户id,粉丝id)
对象存储:
照片:分布式文件存储、HDFS
数据库大小估计
-
用户表
一行 = UserID(4 字节)+ name(20 字节)+ email(32 字节)+ DateOfBirth(4 字节)+ CreationDate(4 字节)+ LastLogin(4 字节)= 68 bytes
5亿用户 = 5亿*68~=32GB -
照片表
一行 = PhotoID (4 bytes) + UserID (4 bytes) + PhotoPath (256 bytes) + PhotoLatitude (4 bytes) + PhotoLongitude (4 bytes) + UserLatitude (4 bytes) + UserLongitude (4 bytes) + CreationDate (4 bytes) = 284 bytes
每天 = 2M * 284 字节 ~= 0.5GB 每天
10年 = 1.88TB -
关注表
每行 = 8bytes
5 亿用户 * 500 个关注者 * 8 字节 ~= 1.82TB -
总量
32GB + 1.88TB + 1.82TB ~= 3.7TB
高级设计
功能
- 上传照片,
- 数据库记录元数据,
- 照片存入对象存储
- 查看、搜索照片
每个用户关注用户的照片消息
详细设计
功能设计
查询用户关注热点消息
为一个用户获取他关注的、最新的、受欢迎的、前100张照片
- 获取关注用户列表
- 获取每个用户100张照片元数据
- 所有照片按时间排名
- 取前100返回
缺点1:延迟高
优化1:新建UserNewsFeed表,预先生成最新消息存储,访问返回然后再次生成
缺点2:非实时
优化2:独立的服务持续生成
时间排序-photoId设计
将照片创建时间作为 PhotoID 的一部分。由于我们将在 PhotoID 上有一个主索引,因此可以很快找到最新的 PhotoID。
photoId = 时间/s + 序列id
如何推送消息(推送技术)
- 客户端 拉取
客户端用户拉取;
缺点:有可能没有新消息,拉空的情况 - 服务端 推送
有新消息立即推送给用户,客户端要维持长轮询接收更新;
缺点:关注人数多服务器推送频繁 - 混合
1000+粉丝用户用拉取,0-1000粉丝的用户用 推送
以一定的缓慢频率向所有用户推送
高可用
读写分离
上传照片慢,写入请求会挤压读取请求流量
加上web服务器有连接限制,应该 拆分读写服务
upload image service
download image service
缓存、负载均衡
- 用户来自全球,在各地用照片缓存服务器+CDN加速
- 用28法则构建缓存,热点数据放入Memcache、redis。 驱逐策略用LRU
可靠性、单点故障
-
负载均衡
upApp
dowApp -
副本备份
metadata
object
元数据分片
方案1 userid 水平分片
通过 唯一 userid 水平分片 用户表、照片表,一个用户的信息与照片metadata落在一个分片上
photoId = 分片id + 递增id
- 缺点:
存储不均匀:某些用户大量照片记录;大量照片记录在一个分片,导致高负载
如果照片记录再分在多个分片,会导致延迟更高
热点用户照片处理
方案2 photoId 水平分片
生成唯一 photoId 分片
-
生成id方式1:数据库序列递增
数据库单点故障:用两台数据库服务,一个生成偶数,一个生成奇数,负载均衡使用 -
生成id方式2:提前生成唯一
-
生成id方式3: 雪花
可扩展
规划更多的逻辑分区。映射数据库
可以方便扩展多台数据库服务