关于 Feed 流的几个热门问题

0x00 前言

本篇聊一下 Feed 流技术,由于这个话题在业界有丰富的实践经验,所以我特意选了个小的切入点,从相对微观的角度说几个具体的问题,避免一些无意义的重复。希望提炼实践中的具体问题来做讨论,使事情变得更有实际意义。

0x01 先行资料

0x02 关于模型

当要做一个 Feed 流,摆在我们眼前的第一个问题就是到底选推模型还是选拉模型,因为这个选择将影响接下来一系列的架构方式。

  • 推模型 or 拉模型

推模型和拉模型各自的优缺点已经被罗列了很多了,比如推模型的存储量大,或者拉模型的效率可能低,但如果你从无到有做这个事情,这些优缺点的罗列还是无法帮助你做出最初的决定,所谓的“知道了许多道理,还是过不好这一生”,当然除非你有实际的构造大流量 Feed 流的经验。

然而根据我们的经验:基于正确规范的架构和基础设施,对于一个千万日活量级的应用 Feed 流, 拉模型完全可以扛得住。

我想,上面这个结论是很有意义的,尤其是对中小创业公司,因为拉模型本身节省存储资源,开发成本低,上线速度快,在业务爆发之前做这样一个 Feed 流,有这样一个明确经验可以帮助你快速做出决定。

另外,上面说的千万日活,并不是说就是拉模型的上限,而是说,如果你做到千万日活,你将会有丰富的实践经验帮助你走下一步,那时也会有更多的资源让你使用,是继续深挖拉模型潜能,还是上推拉结合消灭性能问题,将是另外一个够挑战的问题了。

  • 推模型的原罪

上一节我的描述有些极端,本意上我是想给出更明确的实践结论,因为对于推拉模型的积累对比已经够多了,现在难的似乎是做决定时的信心。那这一节,我就来聊推模型的几个问题。

耗存储。推模型可以理解为给每个粉丝维护一个单独的存储,举例来说,如果某个大 V 有一千万粉丝,他发的一条内容,将被存储一千万份,这个存储放大是非常可观的。于是这里就会常见的问题:一、有多少存储资源能用,这些资源贵不贵?二、如果省掉这些资源存储,响应时间性能到底能打多少折扣,这些折扣值不值?这是个时间和空间的冲突,程序员每天都在做这种问题的衡量,每个系统的要求基准也不一样,我就不妄下结论了。

写峰值。推模型有一个写峰值的问题,通常,我们做推模型,给粉丝写数据的时候一般是离线的,也就是大 V 发布完内容,触发离线写任务推给各个粉丝。可大 V 是少数,大部分时候,都是普通用户在发布,写任务没有那么多,这时,离线写任务的 worker 数可能用不了几个,可一旦大 V 发布了内容,这个写任务会骤增,突然来一个大峰值,如何处理这个峰值是个问题。有些方案:一、把资源调度系统做的超级棒,worker 数量自动化跟着调整,峰值来了的时候,worker 自动迅速扩容,消费离线任务,并在离线任务处理完毕之后缩容,避免资源浪费,这个调度确实需要很棒,因为大多时候,Feed 流对这些任务的要求是很严苛的,比如,产品上希望粉丝至少也是在分钟级看到大 V 发的内容,甚至秒级,这对调度系统的挑战是巨大的。二、推拉结合,大 V 走拉模型逻辑,这个方案的问题就是,你其实做了两套系统,开发成本大。

避不开的业务逻辑。这一点是从业务逻辑开发上来说的,这个也是在具体业务开发过程中推模型让人觉得很难受的点,就是:当我解决很多问题之后,从业务逻辑开发层面,我还是避不开很多业务逻辑。为什么这么说呢,就是在推模型里,每个粉丝都存有一个属于他的数据,但这部分数据在接口设计和数据返回上,也仅仅就是元数据,这份元数据,还是要经过很多处理才能返回给用户,比如过滤、Format,我们希望推模型维护的那个存储是一份尽可能干净的数据,但事情却没那么简单。

不过,以上是我个人的一些总结,由于在推模型上我没有走的更远,这些问题到底是不是真正的问题,欢迎来喷。

0x03 关于数据

模型的事情就不过多说了,再来聊几个关于数据的具体问题。

  • 有状态与无状态

这是 Feed 流的 API 接口设计相关的问题。

举个例子,在拉取 Feed 流数据时候, API 层面基于数量 offset/limit 的分页方案是完全不行的,因为用户 Feed 流的新数据会 insert 到流最开始位置,仅仅给出 offset 会导致分页数据错乱,所以会给出一种 after/limit 的分页方案,就是有一个标志数据,意义是“从 after 这个数据向后取 limit 条数据”;但是,这仅仅是一个干净的 Feed 流的情况下,在实际的业务需求中,Feed 流中的数据会更复杂,复杂到打乱这个看起来可行的分页方式。

以分页这个例子来说,它为什么会这么脆弱呢? 我总结是因为 API 的数据请求是无状态的,用户在取第二页数据的时候,并不知道取第一页数据时到底发生了什么,仅仅知道在接口层面传递的几个值(offset/after/limt),而许多时候尤其是对于 Feed 流的一些时候这些值不够用,导致数据拉取变得棘手。

所以,如果 Feed 流的数据获取是有状态就好了,就像浏览器与服务器之间的 Session,保持用户一个访问周期的上下文数据,这样想做什么就都好做了。

  • 数据 Format

通常,Feed 流中的数据会来自多个不同的源,最后返回给用户之前需要做数据的 Format,这个过程是个性能黑洞,经常包含了很多 IO,你可能要读大量存储,读大量 RPC来获取到数据才能成功组装。所以针对数据 Format 有很多性能优化的点,包括不限于:消灭慢查询、减少调用放大、并行获取数据、做好缓存、操作批量。

要做好性能优化,好的结构是必需的,比如要减少调用放大,那就要尽量保证数据复用和批量获取,只有你的代码结构好,才会有更合适的地方去获取数据和复用数据;也同样,只有你把可以并行部分都很清晰的摘离出来了,才能更合适地去做统一并行。

而诸如消灭慢查询、做好缓存,此类其他细节也都是重要的,这里就不展开。

  • 过滤

几乎所有的 Feed 流都有过滤需求,比如对已经读过的内容进行过滤,或者对已经被作者删除的内容进行过滤。

过滤是个具体的事情,有的时候你仅仅需要元数据就能过滤,有的时候你需要对拿到完整数据才能过滤。总结一句话就是过滤的繁琐与否取决于产品需求,但好的结构可以让过滤变得更符合逻辑,性能表现更好。

0x04 结语

Feed 流是个不小的系统,三言两语只是管中窥豹,长时间没写分享文章了行文也变得不太流畅,希望看完这篇你会有所收获吧。

打赏支持我写出更多好文章,谢谢!

打赏作者

打赏支持我写出更多好文章,谢谢!

任选一种支付方式

1 1 收藏 评论

关于作者:v7

微博:@_v7__ 个人主页 · 我的文章 · 17 ·   

相关文章

可能感兴趣的话题



直接登录
跳到底部
返回顶部