在微博中每个人关注的人会成百上千,在知乎上关注了人还关注话题关注特定主题,这些feed的输出,如何能有效降低系统查询负载,特别是知乎上feed流的结果还需要特定排序。不知道这些都是如何优化的,能否指点一二?
修改
按票数排序
按时间排序
3 个回答
谈谈知乎的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的生成也是这样,如果有必要,我们也会对这些方案做调整,目的都是一样,那就是又对又快又稳定。
如果有什么错误,希望大神指出。如果有更好的方案或者建议,欢迎交流。
虽然我不是技术大佬。
简单来说,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的生成也是这样,如果有必要,我们也会对这些方案做调整,目的都是一样,那就是又对又快又稳定。
如果有什么错误,希望大神指出。如果有更好的方案或者建议,欢迎交流。
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条动态,没有出现在我的首页。
根据这个现象,知乎的首页应该是 写扩散更多些。
而且,在写扩散的时候,貌似写失败了,就拉倒了。
有三种基本思路:
思路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条动态,没有出现在我的首页。
根据这个现象,知乎的首页应该是 写扩散更多些。
而且,在写扩散的时候,貌似写失败了,就拉倒了。