您的位置:首页 > Web前端

微博和知乎中的 feed 流是如何实现的

2015-01-23 14:03 211 查看
在微博中每个人关注的人会成百上千,在知乎上关注了人还关注话题关注特定主题,这些feed的输出,如何能有效降低系统查询负载,特别是知乎上feed流的结果还需要特定排序。不知道这些都是如何优化的,能否指点一二?修改

举报7
条评论 分享 • 邀请回答

按票数排序按时间排序


3 个回答

赞同16
反对,不会显示你的姓名




冯世鹏,知乎工程师

石佛慈悲止戈Cassie 等人赞同

谈谈知乎的Feed。

虽然我不是技术大佬。

简单来说,Feeds这块主要包括两块内容,就是生成feeds和更新feeds。生成feeds是什么意思呢,比如我们已经关注的人做了特定操作,我们需要把这些活动加入你的feeds,让你接收到。更新feeds包括的内容比较多,一种就是你关注点做了更新,比如你新关注了一个人,需要把他的活动加入已有feeds,与此类似,取消关注也一样;另一种就是你的关注点做了一些更新操作,比如你关注的一个人取消关注了一个问题。

我们先来谈feeds生成,用户A做了某操作,比如关注了一个问题,这时候我们首先找到用户A的所有关注者,然后给需要推送的关注者推送此操作,大家可以把每个人的feeds简单想象为一个有序列表,推送很简单,就是在每个人的列表末尾添加这个操作。怎么样,是不是很简单,:)

然后我们谈feeds更新,第一种情况和第二种情况其实都是一样的,我们需要针对这些活动更新来更新feeds,比如我们新关注了一个人,这时候我们需要取出此人的活动历史,然后按照时间顺序把这些历史塞到你的feeds中。此操作的复杂度会比较高,需要使用合适的数据结构来达到最佳性能,目前是O(log(N))。

当然,真实情况并没有这么简单,还有很多其他逻辑和注意点,比如我们的feeds需要对多人做同样的操作做合并(大家可以自行把以上的feeds有序列表变为有序集合),同样的内容的创建时间是要按最新操作的时间来计算的,一个人连续做很多操作需要对操作做合并等。所有大家看到的feeds相应的存储考虑到性能都会使用内存,除此之外所有的操作都需要做持久化存储,否则我们也就没法更新feeds了:)

下面我们谈谈这里面的技术挑战和相关技术,此部分与知乎目前的技术决策和使用技术无关,我给大家分享几个国外团队的工程决策和他们的优化手段。

先来谈谈strava,他们使用了Kafka分布式发布订阅消息系统,这个系统用来事件(event)发布,还使用了Storm分布式实时计算平台,这个计算集群会订阅Kafka的事件,然后完成相应的处理,在这块他们做了一个优化,就是一个事件不会推给所有关注者,只会推给活跃的用户(如何判定一个用户为活跃的,这就看实际情况和数据自己优化了)。

然后再来谈谈Instagram,他们产品的读写比例达到了100:1,事实上大部分互联网产品都是这样,所以这也是推技术更合适的原因,推一次开销可能大一点,不过推(也就是写)发生次数大大少于读,因为有些大牛关注者非常多,达到几百上千万,为了进行可靠地推,这个过程都会异步后台执行。同样,我们需要一个任务调度器和消息队列,任务调度他们选用了Celery,下面需要选择一个消息队列,Redis依赖订阅者轮询,不自带复制备份,而且强依赖内存是个硬伤,不合适;Beanstalk其他方面不错,可还是不支持复制(Replication),弃掉;最后他们选用了RabbitMQ,快,高效,支持复制,而且和Celery高度兼容。

接着谈谈Pinterest,重心在于创建一个智能化的feed,也就是feed会包括一些热点和推荐,而且会根据特定算法来排序。当事件发生后,会经过一系列流程最后才进入用户的内容feed,首先经过智能feed worker来处理,这些worker会接收事件而且根据特定用户给事件打分,然后这些事件会被插入到一个排好序的feed池中,不同类型的事件会被插入各自的池中,目前他们使用HBase的基于key的排序实现了此优先队列,接着智能feed内容生成器接手了,它会从几个池中根据策略取出feeds甚至剔除一些feeds,最后面向用户的智能feed服务会整合旧的feed和新生成的feed,展现给用户看到的Home
Feeds。

最后简单谈谈Facebook,用户量大了之后对工程团队要求会更高,每个facebook用户都会有一个属于自己的独一无二的动态生成的首页。很多团队都会用用户ID为Key来把feeds存入Key-Value存储系统,比如Redis,问题是通过网络连接做远程过程调用非常慢,无法满足实时性的要求,所以facebook团队也开始使用了嵌入式数据库,他们也开源了自己在用的RocksDB

这些内容都在他们的技术博客里面有提到,链接在这里:
Strava Engineering
How Instagram Feeds Work: Celery and RabbitMQ
Making Pinterest
https://www.facebook.com/notes/10151822347683920/

就像电影特效是为剧情服务一样,技术是为产品服务的。针对不同的业务场景,适合的技术也是不一样的。随着产品的调整和业务规模的扩大,相应的技术都会做进化和调整。针对不同的难题,需要提出不同的技术方案,feeds的生成也是这样,如果有必要,我们也会对这些方案做调整,目的都是一样,那就是又对又快又稳定。

如果有什么错误,希望大神指出。如果有更好的方案或者建议,欢迎交流。

编辑于 2014-11-05 6
条评论        




ganxious
ganxious,信可乐也

CoderRobin郑毅 赞同

先不考虑数据的物理分布,仅讨论下业务的设计。

有三种基本思路:

思路1,产生的所有动态,都在同一条索引上,上面承载所有的更新,以及读取。每个用户都有自己的filter规则,这个规则包括「屏蔽了谁,关注了谁,屏蔽了哪个问题」。

用户在读取feeds,便是使用自己的filter,按照时间顺序,从头遍历这个索引,直到得到足够的条目。

优点:业务逻辑上是最清晰,性能稳定。

缺点:技术难度最大。

思路2,读扩散。

每个人有自己产生的feeds队列,打开自己的首页时,按照自己的关注列表和屏蔽规则,去读取其他用户的feeds队列,然后汇总、排序。

优点:实现最简单,关注列表 敏感性最高。

缺点:性能最差,而且差的很稳定。

思路3,写扩散。

每个人有自己的产生的feeds队列和 待读取的feeds队列。每个用户产生动态时,压入到关注者的 待读取feeds队列,压入前,需要根据屏蔽规则来判断下是否要压入。

优点:每个用户页面打开的速度是最快的,性能最高。

缺点:关注列表变化时,敏感度略低,但读取队列的时候,再根据规则过滤一遍,也没啥太大问题。

个人推荐:思路1 。

根据个人的简单测试,知乎的首页,貌似是 思路3+思路2 。

猜测的理由:

1-当我取关时,刷新,页面还会有这个用户的动态,所以 思路3的可能性很大。

2-当我新关注一个人,刷新,页面上会有这个用户的动态,可能针对最近产生的关注行为做了特殊处理,少量的做了读扩散。

-----------------------

update at 2014-12-08

我今天偶然的发现,我关注的某些人的回答,是没有出现在我的首页的。

我反复对比过,估计 大概是4天前的4、5条动态,没有出现在我的首页。

根据这个现象,知乎的首页应该是 写扩散更多些。

而且,在写扩散的时候,貌似写失败了,就拉倒了。

编辑于 2014-12-08 5
条评论        

赞同0
反对,不会显示你的姓名




咚咚,诗书继世长

早在人人火了,UChome出来的时候大家就在研究各种feed流的实现,到微博这会儿应该已经没啥人在讨论了,各种推和拉模式,网上搜搜就知道了。

关于排序又是另一个问题了,这个方面大家都在探索吧。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: