恰好最近想写一个Feed机制的文章,就来回答一下吧。
楼上各位其实把大致的状况都已经说的很明白了,我来分享一下咱们目前线上一个feed实现机制,已经在生产环境运行了大半年。理论来讲,百万级别用户没有什么问题。
为了节省你们流量,全程无图(实际上是我懒得画 - - ),但愿你们能把省下的流量钱来给我发红包,鼓掌 。
首先,抛去数据库这一块,数据库我想你们确定知道怎么设计,可是查询确定是个麻烦事, 因此我使用了redis进行一个冗余设计,开始介绍以前,须要了解什么是推拉模式,楼上说的两篇文章
新浪微博架构和FEED架构分析--人人架构_paper0023_新浪博客 ,还有推拉模式以及时间分区拉模式的分析
微博feed系统的推(push)模式和拉(pull)模式和时间分区拉模式架构探讨 其实已经足够了解了,请各位看官若是未对推拉模式了解,那么请先看文章,再来看个人回答,个人回答只是阐述具体实现,谢谢。
那么我如今说一下redis这块怎么来完成推拉模式,以及内存尽量节省,速度尽量提升吧(固然,只是我理解的节省内存跟速度提升,若是看官们有其余的意见,我就两点要求,1、轻喷,2、说完再喷)。
一、实现
首先,先解决发布跟接收的问题,目前有大致如下几种方式:
一、推模式
什么是推模式?推模式就是,用户A关注了用户B,用户B每发送一个动态,后台遍历用户B的粉丝,往他们粉丝的feed里面推送一条动态。
二、拉模式
与推模式相反,拉模式则是,用户每次刷新feed第一页,都去遍历关注的人,把最新的动态拉取回来。
可是,无论推模式仍是拉模式都存在若关注数量或者粉丝数量过多,致使遍历时间太长的问题,怎么去解决 ?这里就出现了第三种模式,推拉模式。
三、推拉模式
这是一种折中的解决方案,就是在线推,离线拉。粉丝几百上千万, 跟你发布动态同时在线的确定也就只有那么顶天几百几千几万,况且这类大V不多,只推给在线的粉丝,离线的粉丝上线后,再去拉取动态便可!可是,无论是什么模式,每一个用户都会维护一个相似发件箱跟收件箱的东西,保存本身发过的动态以及Feed动态(具体实现看下面),来完成推与拉。
而这里讲的,确定就是推拉模式,用户A关注了用户B , 用户B发布动态则将动态推动用户A的feed,这里使用redis的zset实现,sort为time(记得以毫秒为时间戳,秒级在数据量达到必定程度后,会有读取不到的问题,好比以时间戳为分页页码),value为具体的动态 ID(为何是动态ID, 其实很简单, 就是由于动态的内容能够进行缓存,在redis里面所有走ID,修改动态内容也须要修改一处,动态内容能够保存在hash结构里), 每一个用户维护一个zset保存我发布的动态,一个zset保存个人feed动态,过时时间3~7天看状况而定。为何要设计过时时间后面会细说。
OK,全局维护一个在线用户列表,怎么设计这个就本身琢磨了,为了防止用户挂后台致使与服务端为离线状态,因此最好是1~3小时未操做或者离线时间不大于3小时的,都当作在线处理,反正这个看状况定。
那么,当用户发了一条动态后,后台会有如下这些操做:
在线推: 异步遍历在线的粉丝,将动态ID,添加到粉丝的Feed中。
离线拉: 离线用户打开APP后,咱们是会请求一个公共的入口接口,主作统计以及其余初始化操做,在这里,咱们也开了一个异步线程,对用户进行Feed更新操做,防止用户进入APP后等待拉取时间过长,毕竟关注成千上万的人确定有(其实万单位如下遍历都很快)。拉取过程其实就是把本身最后一条Feed的时间戳取出,去遍历关注的人的feed,将大于该时间的ID所有拉取回来。用户进入APP后,刷新便可看到最新操做。
另:若是有Feed新消息数提示的需求,能够在推拉的同时进行增长, 刷新feed时清空便可。
其实到这里,发布接收的问题已经解决了,那么有一个问题,用户feed里面过长,占用内存怎么办?
我是这么处理的,一个用户的feed第一次拉取的时候,feed长度为500条,在咱们APP里,至关于50页,然后的数据,都走数据库。大页码翻页其实就是个伪需求并且耗性能的东西,用户除了第一次用这个APP,才会翻到底,第一次使用, 能有几个动态 ?而对于二次使用以上的用户,通常来说, 翻了几页就已经到达上一次看过的地方了,因此500条数据,在关注量通常的状况下,内容已经足够消费,甚至达到疲劳,可能有关注量很大的用户他的Feed天天可能有不少不少动态,可是,不用说,确定是作广告的,关注一堆人等着回粉,这种人更不会去消费内容,50页的内容,翻起来都累。固然,并非说放弃了这些人,feed找不到走数据库嘛~~~~爱走不走,想走就给我翻50页再说~
还有一个问题,每一个用户都维护本身的动态跟Feed队列,当用户上百万时,内存的占有量确定不小,要怎么释放内存才合适 ?
这里就回到上面那个问题了,为何要给feed的key设计过时时间?为何是设计3~7天过时时间?
缘由有如下:
1、一个用户3~7天不打开APP,可能已经对APP失去兴趣了,打开概率很小,或者已经被卸载了,没有存在的意义了。
2、3~7天未登录APP,关注的人发的动态也很多了,Feed未拉取回来的数据确定也很多,那么这时候去遍历其实拉取量很大,那么还不如直接所有从新拉一边或者拉取用户最后登录时间后产出的数据。
到这里,其实已经差很少了,大部分业务逻辑已经足够知足,而且速度也理想,目前咱们线上这种模式走了半年,feed通常都是10~80ms响应完毕。
好了,大概就是这样了。
最后说一句:
<?php
echo 'php 是世界上最好的语言!!!';
?>