1.方案一
推模式(写扩散):
1.用户发表的内容插入到所有粉丝的接收队列里,粉丝拉取关注流从自己的接收队列里拉取
2.用户撤销发表,从每个粉丝的队列里删除掉
3.新粉丝新关注了此用户,将该用户的发表内容插入到新粉丝的队列里
4.新粉丝取消关注了此用户,将该用户的有关内存,从该粉丝的队列里删除
优点:
1.消除了拉模式的IO集中点,每个用户都读自己的数据,高并发下锁竞争少
2.拉取关注流的业务流程简单,速度快
3.拉取不需要进行大量的内存计算,网络传输,性能很高
缺点:
1.极大消耗存储资源,数据会存储很多分,比如大V的粉丝有一百万,他每次发表一次,数据会冗余一百万份,同时,插入到一百万的粉丝的队列中也比较费时。
2.新增关注,取消关,发布,取消发布的业务流程复杂。
优化点:先推给在线用户
离线用户上线再拉取
2.方案二
拉模式(读扩散):
1.用户发表的内容只插入到自己的队列里去,粉丝拉取关注流里需要从每个关注人的队列里各取几个,然后进行rank。
2.用户撤销发表,只把自己的队列对应的删掉即可。
3.新粉丝新关注了此用户,因为是拉模式,不需要额外操作,刷新关注流的时候就会拉取。
4.粉丝取消关注了此用户,因为是拉模式,不需要额外操作。
优点:
1.存储结构简单,数据存储量小,只存一份,无数据冗余。
2.关注,取关,发布,取消发布的业务流程非常简单。
3.存储结构,业务流程都比较容易理解,适合项目早期用户量、数据量、并发量不大时的快速实现。
缺点:
1.拉取业务流程比较复杂
2.有多次数据结构访问,并且要进行大量的内存计算,网络传输,性能较低。
3.有大v效应
拉模式优化时间分区:
发布的表可以按照时间区间分表,一天表,一周表,一个月表,总表等,简单来说就是做几份数据冗余。
用户登录时,我们根据用户的上次登录的时间确定他适合查询那个区间表。
举例:对于每天都登录的用户定位到一周表,半个月登录一次的,定位到一个月表,依次类推。
优点:解决单个表(单个队列)的性能问题。
缺点:
1.实现复杂。
3.方案三
推拉结合:
1.发表
1).发表内容先进入一个队列服务
2).从粉丝列表中读取到自己的粉丝列表,以及判断自己是否大V
3).将发表内容写入个人的发表队列(现在就是进入到动态发表库里),如果是大V,就结束了
4)如果不是大V还需要将自己的发表内存插入到自己粉丝的接收队列里去
2.拉取
1).去关注表里拉取关注的人,并判断谁是大V
2).去读自己的接收队列
3).去遍历大v的发表队列
4).进行rank
3.取消关注
1).取消的如果是大v,见拉模式
2)取消的如果不是大v,见推模式
4.取消发布
同取消关注
5.增加新关注
1)如果新关注的是大v,见拉模式
2)如果关注的不是大v,见推模式。
优点:
1.无推模式的那么多的数据冗余
2.无拉模式的大量计算
缺点:
1.业务比较复杂,多少粉丝算大v值得衡量,大v如果很少,就会退化为推模式。很多就会退化为拉模式
2.大v风险,一个特别爆的话题,导致大家都去关注,拉取关注流,容易造成存储该大v的机器宕机。拉模式都存在这个问题
推拉结合优化:
1.推优化:参考推模式优化
2.拉优化:参考拉模式优化
其余问题:
大v退化成非大v:需要一个大v标识,都变非大v时,去掉这个标识,同时开启一个异步任务,将它的发表队列里的插入到粉丝的队列里去。插入的数据条数,取决于需求中的保留粉丝队列中的多少条
非大v进化成大v:这个不会有啥问题,旧的已经插入了粉丝队列里面了,新的去拉就可以了。
总结:
以上的方案大家都要根据自己的业务来选择,想推拉结合虽然很全面,但实现复杂,同时业务量很大时才有用。
存储选型
| 性能 | 可用性 | 扩展性 | 成本 | 开发成本 |
---|---|---|---|---|---|
pika 方案1 | 8分 | 7分 | 10分 | 8分 | 8分 |
redis cluster 方案2 | 10分 | 8分 | 10分 | 9分 | 8分 |
mongo分库分表 | 6分 | 10分 | 8分 | 10分 | 9分 |