目录
问题:需要设计一个类似Acwing新鲜事的系统
1.明确设计需求
首先列举一些需要的功能,找出核心功能:
- 登录/注册
- 用户信息
- 上传图片
- 发布新鲜事
- 评论/点赞/收藏
- 消息流(News Feed)
- 时间轴(Timeline)
- 关注/取关
- …
接下来做一些简单的计算,假设系统每天有1百万活跃用户(问面试官),平均每个用户每天产生60个请求(猜的)。
QPS = 1M * 60 / 86400 ~ 700
峰值 QPS = 700 * 3(猜的) ~ 2k
服务器和数据库各用2~3台就足够了
2.设计服务
针对核心功能,大概可以分成以下几个服务
- User Service: 登录/注册
- Message Service:发布新鲜事,消息流,时间轴
- Friendship Service:关注/取关
3.存储结构设计
什么是新鲜事
- 登录后你可以看到的消息流
- 包含你自己/关注的人发的消息集合
- 每个人看到的都不一样
消息流的实现方式
消息流一般有两种实现方式,Pull和Push
Pull模式
用户查看的时候,获取每个好友的前100条内容,合并取出前100条(一般来说足够了,很少有人会去翻这么多条)。
实现算法可以参考 LeetCode 23. 合并K个升序链表
每次查看消息流,如果用户有n个关注,就会产生n次数据库读取
每次发布新鲜事,会产生1次数据库写入
缺点:多次读取数据库,整个请求过程会比较慢
Push模式
为每个用户创建一个list来存储他的信息流内容,
用户发一个新鲜事后,把这条新鲜事逐个推送到被关注人的list中,
当用户需要查看的时候,从list中返回前100条。
每次查看信息流,会产生一次数据库读取
每次发布新鲜事,如果用户有n个粉丝,会产生n次数据库写入,
但是写入过程可以通过异步任务在后台执行,用户不用等待
缺点:粉丝数量过大处理不及时,磁盘空间占用较多
4.系统优化
一般从两个方面考虑,一个是系统设计缺陷/拓展,另一个是维护方面的问题
系统设计缺陷/拓展
- Pull/Push模式的优缺点怎么处理
- 添加一些其他功能,比如:点赞,关注,广告
维护方面
- 服务器/数据库挂了怎么处理
- 流量突然暴增
Pull/Push模式
- Pull模式主要会造成数据库多次读取,响应时间较慢,一般可以通过使用缓存进行优化。
- Push模式会占用硬盘空间,但相比于Pull模式占用的内存空间,可以不用在意。
- Push模式对于不活跃的用户是否有必要进行推送,还有就是如果用户的粉丝数量远远大于关注数量,每次全粉丝推送依然会有很大开销,一次异步处理可能需要几个小时。
Pull和Push模式结合优化
- 对于普通用户,仍然使用Push模式
- 对于明星用户,不主动Push到用户的信息流
- 当用户需要的时候,到明星用户的时间轴中取数据,合并到自己的信息流中
Pull和Push模式使用场景
Pull模式适合对实时性有要求,用户会经常发布新鲜事,会有明星用户问题存在的系统。
Push模式则基本相反,适合对实时性要求不高,用户不会经常发布新鲜事,用户之间一般是双向关注,例如朋友圈。
关注/取关功能
当关注了一个用户的时候,异步的将他的时间轴合并到自己的信息流中。
当取关了一个用户的时候,异步的将他发过的新鲜事从自己的信息流中删除。
好处是用户可以立刻获得反馈,操作成功。
缺点是用户取关后刷新,发现内容还在,但是过一段时间后就不见了。