系统设计 —— Feed 流
2019-08-12 本文已影响0人
GOGOYAO
参考资料
如何打造千万级Feed流系统
TableStore Timeline:轻松构建千万级IM和Feed流系统
Design the Twitter timeline and search
Feed系统架构资料收集
1. 表结构
1.1. Feed 内容库
内容库用于存储用户发送的消息。
列名 | 是否主键 | 说明 |
---|---|---|
user_id | yes | 消息发送者的 id |
message_id | yes | 消息 id,可以用时间戳 |
content | no | 消息内容 |
other | no | 其他信息 |
1.2. 同步表
同步方式,常见的方式有三种:
- 推模式(也叫写扩散):和名字一样,就是一种推的方式,发送者发送了一个消息后,立即将这个消息推送给接收者,但是接收者此时不一定在线,那么就需要有一个地方存储这个数据,这个存储的地方我们称为:同步库。推模式也叫写扩散的原因是,一个消息需要发送个多个粉丝,那么这条消息就会复制多份,写放大,所以也叫写扩散。这种模式下,对同步库的要求就是写入能力极强和稳定。读取的时候因为消息已经发到接收者的收件箱了,只需要读一次自己的收件箱即可,读请求的量极小,所以对读的QPS需求不大。归纳下,推模式中对同步库的要求只有一个:写入能力强。
- 拉模式(也叫读扩散):这种是一种拉的方式,发送者发送了一条消息后,这条消息不会立即推送给粉丝,而是写入自己的发件箱,当粉丝上线后再去自己关注者的发件箱里面去读取,一条消息的写入只有一次,但是读取最多会和粉丝数一样,读会放大,所以也叫读扩散。拉模式的读写比例刚好和写扩散相反,那么对系统的要求是:读取能力强。另外这里还有一个误区,很多人在最开始设计feed流系统时,首先想到的是拉模式,因为这种和用户的使用体感是一样的,但是在系统设计上这种方式有不少痛点,最大的是每个粉丝需要记录自己上次读到了关注者的哪条消息,如果有1000个关注者,那么这个人需要记录1000个位置信息,这个量和关注量成正比的,远比用户数要大的多,这里要特别注意,虽然在产品前期数据量少的时候这种方式可以应付,但是量大了后就会事倍功半,得不偿失,切记切记。
- 推拉结合模式:推模式在单向关系中,因为存在大V,那么一条消息可能会扩散几百万次,但是这些用户中可能有一半多是僵尸,永远不会上线,那么就存在资源浪费。而拉模式下,在系统架构上会很复杂,同时需要记录的位置信息是天量,不好解决,尤其是用户量多了后会成为第一个故障点。基于此,所以有了推拉结合模式,大部分用户的消息都是写扩散,只有大V是读扩散,这样既控制了资源浪费,又减少了系统设计复杂度。但是整体设计复杂度还是要比推模式复杂。
用图表对比:
对比项 | 推模式 | 拉模式 | 推拉结合模式 |
---|---|---|---|
写放大 | 高 | 无 | 中 |
读放大 | 无 | 高 | 中 |
用户读取延时 | 毫秒 | 秒 | 秒 |
读写比例 | 1:99 | 99:1 | ~50:50 |
系统要求 | 写能力强 | 读能力强 | 读写都适中 |
常见系统 | Tablestore、Bigtable等LSM架构的分布式NoSQL | Redis、memcache等缓存系统或搜索系统(推荐排序场景) | 两者结合 |
架构复杂度 | 简单 | 复杂 | 更复杂 |
介绍完同步模式中所有场景和模式后,我们归纳下:
- 如果产品中是双向关系,那么就采用推模式。
- 如果产品中是单向关系,且用户数少于1000万,那么也采用推模式,足够了。
- 如果产品是单向关系,单用户数大于1000万,那么采用推拉结合模式,这时候可以从推模式演进过来,不需要额外重新推翻重做。
- 永远不要只用拉模式。
- 如果是一个初创企业,先用推模式,快速把系统设计出来,然后让产品去验证、迭代,等客户数大幅上涨到1000万后,再考虑升级为推拉集合模式。
- 如果是按推荐排序,那么是另外的考虑了,架构会完全不一样,这个后面专门文章介绍。
同步表的结构如下:
列名 | 是否主键 | 说明 |
---|---|---|
user_id | yes | 消息接收者用户ID |
sequence_id | yes | 消息顺序ID,可以使用timestamp + send_user_id,也可以直接使用Tablestore的自增列。 |
sender_id | no | 消息发送者的用户ID |
message_id | no | store_table中的message_id列的值,也就是消息ID。通过sender_id和message_id可以到store_table中查询到消息内容 |
other | no | 其他信息 |