4 从小白到架构师: Feed 流系统实战

「从小白到架构师」系列努力以浅显易懂、图文并茂的方式向各位读者朋友介绍 WEB 服务端从单体架构到今天的大型分布式系统、微服务架构的演进历程 。读了三篇万字长文之后各位想必已经累了(主要是我写累了),今天我们回来看看小明和他的「淘金网」的故事 。
「淘金网」里有一个页面叫「关注页」,关注页的逻辑十分常见就是将用户关注的创作者发表的文章聚合在一起,按时间倒序排列即可 。
【4 从小白到架构师: Feed 流系统实战】

4 从小白到架构师: Feed 流系统实战

文章插图
这种产品形态在业内一般被叫做 Feed 流,Feed 流产品在我们手机APP中几乎无处不在,比如微信朋友圈、新浪微博、今日头条等 。只要大拇指不停地往下划手机屏幕,就有一条条的信息不断涌现出来 。就像给宠物喂食一样,只要它吃光了就要不断再往里加,故此得名Feed(饲养) 。
Feed 流产品一般有两种形态,一种是基于算法推荐,另一种是基于关注关系并按时间排列 。「关注页」这种按时间排序的 Feed 流也被为 Timeline 。「关注页」自然的也被称为「关注 Timeline」, 存放自己发送过的 Feed 的页面被称为「个人 Timeline」 比如微博的个人页 。
就是这么个 Feed 流系统让「淘金网」的工程师分成两派吵作一团,一直吵到了小明办公室 。。。
推与拉之争拉模型一部分工程师认为应该在查询时首先查询用户关注的所有创作者 uid,然后查询他们发布的所有文章 , 最后按照发布时间降序排列 。
4 从小白到架构师: Feed 流系统实战

文章插图
使用拉模型方案用户每打开一次「关注页」系统就需要读取 N 个人的文章(N 为用户关注的作者数), 因此拉模型也被称为读扩散 。
拉模型不需要存储额外的数据,而且实现比较简单:发布文章时只需要写入一条 articles 记录 , 用户关注(或取消关注)也只需要增删一条 followings 记录 。特别是当粉丝数特别多的头部作者发布内容时不需要进行特殊处理,等到读者进入关注页时再计算就行了 。
拉模型的问题同样也非常明显,每次阅读「关注页」都需要进行大量读取和一次重新排序操作 , 若用户关注的人数比较多一次拉取的耗时会长到难以接受的地步 。
推模型另一部分工程师认为在创作者发布文章时就应该将新文章写入到粉丝的关注 Timeline,用户每次阅读只需要到自己的关注 Timeline 拉取就可以了:
4 从小白到架构师: Feed 流系统实战

文章插图
使用推模型方案创作者每次发布新文章系统就需要写入 M 条数据(M 为创作者的粉丝数),因此推模型也被称为写扩散 。推模型的好处在于拉取操作简单高效,但是缺点一样非常突出 。
首先,在每篇文章要写入 M 条数据,在如此恐怖的放大倍率下关注 Timeline 的总体数据量将达到一个惊人数字 。而粉丝数有几十万甚至上百万的头部创作者每次发布文章时巨大的写入量都会导致服务器地震 。
通常为了发布者的体验文章成功写入就向前端返回成功,然后通过消息队列异步地向粉丝的关注 Timeline 推送文章 。
4 从小白到架构师: Feed 流系统实战

文章插图
其次 , 推模型的逻辑要复杂很多,不仅发布新文章时需要实现相关逻辑,新增关注或者取消关注时也要各自实现相应的逻辑,听上去就要加很多班 。。
在线推,离线拉在做出最终决定之前我们先来对比一下推拉模型:
优点缺点推读取操作快逻辑复杂消耗大量存储空间粉丝数多的时候会是灾难拉逻辑简单节约存储空间读取效率低下,关注人数多的时候会出现灾难虽然乍看上去拉模型优点多多,但是 Feed 流是一个极度读写不平衡的场景,读请求数比写请求数高两个数量级也不罕见,这使得拉模型消耗的 CPU 等资源反而更高 。
此外推送可以慢慢进行,但是用户很难容忍打开页面时需要等待很长时间才能看到内容(很长:指等一秒钟就觉得卡) 。因此拉模型读取效率低下的缺点使得它的应用受到了极大限制 。
我们回过头来看困扰推模型的这个问题「粉丝数多的时候会是灾难」,我们真的需要将文章推送给作者的每一位粉丝吗?
仔细想想这也没有必要,我们知道粉丝群体中活跃用户是有限的,我们完全可以只推送给活跃粉丝,不给那些已经几个月没有启动 App 的用户推送新文章 。

推荐阅读