百万用户时尚分享网站feed系统扩展实践

朋友圈微博feed流,推拉实践 feed流业务的推拉模式小结: • 拉模式,读扩散,feed存一份,存储小,用户集中访问数据,性能差 • 推模式,写扩散,feed存多份,用冗余存储换锁冲突,性能高 立即下载
摘要:Fashiolista作为一个以社交、分享为主的在线时尚交流网站,其feed系统占据了网站的核心架构,其扩展性至关重要。网站创始人兼CTO撰写博客,分享了自家网站feed系统扩展的经验。

Fashiolista是一个在线的时尚交流网站,用户可以在上面建立自己的档案,和他人分享自己的以及在浏览网页时看到的时尚物品。目前,Fashiolista的用户来自于全球100多个国家,用户达百万级,每日分享的时尚物品超过500万。作为一个以社交、分享的网站,feed系统占据了网站的核心架构,Fashiolista的创始人兼CTO Thierry Schellenbach撰写了一篇博客,分享了自家网站feed系统建设的经验,译文如下:

Fashiolista最初是我们作为兴趣在业余时间开发的一个项目,当初完全没有想到它会成长为规模如此大的在线时尚交流网站。最早的版本开发用了大概两周的时间,当时feed信息流推送系统相当简单。在这里分享一些我们扩展feed系统的经验。


对于许多大型的创业公司,如Pinterest、Instagram、Wanelo和Fashiolista来说,feed是一个核心组件。在Fashiolista网上的 flat feed、aggregated feed和notification系统功能都是靠feed系统来支撑的。本文中将介绍我们在扩展feed系统中遇到的问题,以及你自己方案中的设计决策。随着越来越多的应用依赖于feed系统,理解feed系统的基本工作原理变得至关重要了。

另外,Fashiolista的feed系统Python版本——Feedly已经开源了。

Feed简介

feed系统的扩展问题曾引起过广泛关注,这个解决方案是为了在网络拥挤的情况下,构建一个类似于Facebook新鲜事feed、Twitter流或Fashiolista的feed页面。这些系统的共同点在于向用户展示其关注的人的动态,我们就是基于这个标准来构建动态数据流的,诸如“Thierry在Fashiolista列表中添加了一件服饰”或“Tommaso发布了一条twitter”。

构建这个feed系统用到了两个策略:

  1. 拉取(Pull),读取的过程中收集feed。
  2. 推送(Push),写的过程中提前计算好feed。

大多数实时在线应用程序会使用这两种方法的组合,将动态推送给你的粉丝的过程被称为消息分发(fanout)。

历史和背景

Fashiolista的feed系统经过了三次重大改进。第一个版本基于PostgreSQL数据库,第二个版本使用Redis数据库,目前的版本采用Cassandra数据库。为了便于读者更好的理解这些版本更替的时间和原因,笔者会首先介绍一些背景知识。

第一部分——数据库

第一版本的数据库查询语句很简单,类似于这种:

select * from love where user_id in (...)

令人惊讶的是这个系统的强健性还不错。当love(类似于“赞”了某件服饰)的数量达到百万时,它运行得很好,超过500万时,依然没有问题。我们还打赌说这个系统不能支持千万的数量级,但是当love到达千万时,它依然运行得很好。这个简单的系统支撑着我们的系统达到了百万的用户和过亿的love,期间只进行了一些小改动。之后随着用户的增多,这个系统开始出现波动,部分用户的延时长达数秒,在参考了很多关于feed系统的架构设计之后,我们开发了第一个基于Redis的Feedly。

第二阶段——Redis和Feedly

我们为每个用户建立一个用Redis存储的feed,当你love了一件服饰时,这个动态会分发给你所有的粉丝。我们尝试了一些小技巧来减少内存的消耗(笔者会在下面具体介绍),Redis的启动和保持确实比较简单。我们使用Twemproxy在几台Redis机器上进行共享,使用Sentinel做自动备份。

Redis是一个好的解决方案,但是几个原因迫使我们不得不寻找新的方案。首先,我们希望支持多文档类型,而Redis返回数据库查询更困难,并且提高了存储需求。另外,随着业务的增大,数据库回滚也变得越来越慢。这些问题只能靠在Redis上存储更多的数据来解决,但是这样做的成本太高了。

第三阶段——Cassandra和Feedly

通过比较HBase、DynamoDB和Cassandra2.0,我们最终选择了Cassandra,因为它拥有几个移动部件,Instagram使用的数据库就是Cassandra,并且Datastax为它提供支持。Fashiolista目前在flat feed中完全采取推送流,聚合feed采用推送和拉取混合的技术。我们在每个用户的feed中最多保存3600条动态,目前占用了2.12TB的存储空间。由明星用户带来的系统波动我们也采取了一些方式进行缓解,包括:优先队列、扩大容量和自动扩展等。


Feed设计

笔者认为Fashiolista设计的改进过程非常有代表性,在构建一个feed系统时(尤其是使用Feedly)有几个重要的设计问题需要考虑。

1.非规范化Vs规范化

规范化的方法是,你关注的人的feed列表中是每条动态的ID,非规范的存储是动态的所有信息。

仅存储ID可以大幅度减少内存消耗,然而这意味着每次加载feed都要重新访问数据库。如何选择取决于你在进行非规范化存储时,复制数据的频率。比如构建一个消息通知系统和一个feed系统有很大的区别:通知系统中每个动作的发生只需要被发送给几个用户,而feed系统中每个动态的数据可能要被复制给成千上万的粉丝。

另外,如何选择取决于你的存储架构,使用Redis时,内存是需要特别注意的问题;而使用Cassandra要占用大量的存储空间,但是对于规范化数据来说使用并不简单。

对于feed通知和基于Cassandra构建的feed,笔者建议将你的数据非规范化。而基于Redis的feed你需要最小化内存消耗,并保持数据规范化。采用Feedly可以轻松实现两种方案。

2.基于生产者的选择性分发

Yahoo的Adam Silberstein等人所著的论文中,提出了一种选择性推送用户feed的方法,Twitter目前也在使用类似的方法。明星用户的消息分发会给系统带来突然和巨大的负载压力,这意味着必须要预留出额外的空间来保持实时性。这篇论文中建议通过选择性地分发消息,来减少这些明星用户带来的负载。Twitter采用了这个方法后,在用户读取时才加载这些明星用户的tweet,性能得到了大幅度提升。

3.基于消费者的选择性分发

另外一种选择性分发方式是指对那些活跃用户(比如过去一周登录过的用户)分发消息。我们对这个方法进行了修改,为活跃用户存储最近的3600条动态,为非活跃用户存储180条,读取180条之后的数据需要重新访问数据库,这种方式对于非活跃用户的体验不太好,但是能有效降低内存消耗。

Silberstein等人认为最适合选择性推送模式的情境是:

  1. 生产者偶尔生产动态信息
  2. 消费者经常请求feed

遗憾的是Fashiolista还不需要如此复杂的系统,很好奇业务要达到多少数量级才会需要这种解决方案。

4.优先级

 一个替代的策略是在分发任务时采取不同的优先级,将给活跃用户的分发任务设为高优先级,向非活跃用户的分发任务设为低优先级。Fashiolista为高优先级的用户预留了一个较大的缓存空间,来处理随时的峰值。对于低优先级用户,我们靠自动扩展和点实例。在实践中,这意味着非活跃用户的feed会有一定的延时。使用优先级降低了明星用户对系统的负载压力,虽然没有解决根本问题,但大幅度降低了系统负载峰值的量级。

5.Redis Vs Cassandra

Fashiolista和Instagram都经历了从Redis开始,然后转战Cassandra的过程。笔者之所以会推荐从Redis开始是因为Redis更容易启动和维持。

然而Redis存在一定的限制,所有的数据需要被存储在RAM中,成本很高。另外,Redis不支持分片,这意味着你必须在结点间分片(Twemproxy是一个不错的选择),这种分片很容易,但是添加和删除节点时的数据处理很复杂。当然你可以将Redis作为缓存,然后重新访问数据库,来克服这个限制。但是随着访问数据库的成本越来越高,笔者建议还是用Cassandra代替Redis。

Cassandra Python的生态系统正在发生巨变,CQLEngine和Python-Driver都是很优秀的项目,但是它们需要投入一定的时间去学习。

结论

在构建自己的feed解决方案时,有很多因素需要在节点分片时考虑:选择何种存储架构?如何处理明星用户带来的负载峰值?非规范化数据到何种程度?笔者希望借助这篇文章能够为你提供一些建议。

Feedly不会为你做任何选择,这仅是一个构建feed系统的框架,你可以自己决定内部的技术细节。可以看Feedly的介绍进行了解或参看操作手册构建一个Pinterestsque应用程序。

请注意只有数据库中的用户达到百万时,你才会需要解决这个问题。在Fashiolista简单的数据库解决方案就支撑我们达到了百万用户和过亿的love。

更多关于feed系统的设计,笔者强烈建议看一下这些文章:

原文链接:Design Decisions For Scaling Your High Traffic Feeds(编译/周小璐 审校/仲浩)

5分钟搞定三网话费余额查询:手把手教你用PHP+HTML搭建查询系统(含API调用避坑指南) 本文详细介绍了如何使用PHP+HTML快速搭建三网话费余额查询系统,涵盖API调用避坑指南、前端UI设计及性能优化。通过统一处理移动、电信、联通三大运营商接口差异,实现高可用查询功能,并提供安全防护与生产部署建议,帮助开发者高效构建稳定可靠的话费查询工具。 阅读详情

相关推荐

无监督学习初探:K-Means聚类与主成分分析(PCA)

K-Means适用于快速分组,但对数据分布敏感,可结合轮廓系数评估质量。PCA通过特征值分解实现线性降维,需注意非线性场景的替代方案(如UMAP)。进阶方向:聚类:谱聚类、高斯混合模型(GMM)处理复杂形状。降维:t-SNE、自编码器处理非线性结构。

weixin_69882801的博客 1453

使用 Redis 实现 Feed 流

背景 最近接到一个需求,用一句话来说就是:展示关注人发布的动态,这个涉及到 feed 流系统的设计。本文主要介绍一个一般企业可用的 Feed 流解决方案。 相关概念 下面先介绍一下关于 Feed 流的简单概念。 什么是 feed 流 Feed:Feed 流中的每一条状态或者消息都是 Feed,比如微博中的一条微博就是一个 Feed。 Feed流:持续更新并呈现给用户内容的信息流。每个人的朋友圈,...

dearKundy的博客 4560

用Charles抓包调试iOS应用?这份保姆级配置指南帮你绕过所有坑

本文提供了一份在Mac上使用Charles抓包调试iOS应用的保姆级配置指南。详细讲解了从Charles安装、Mac端代理设置、根证书安装,到iOS设备连接同一WiFi、配置代理以及最关键的系统证书信任等全流程步骤,并分享了SSL代理规则、断点调试等进阶技巧,帮助开发者高效定位和解决网络请求问题。

rice5的博客 638

Redis——实现关注与取关等功能

目录 实现关注与取关 实现共同关注功能 关注推送 Feed流的模式 拉模式 推模式 推拉结合模式 总结 基于推模式实现关注推送功能 Feed流的分页问题 实现关注推送页面的分页查询 实现关注与取关 实现 Controller层 @RestController @RequestMapping("/follow") public class FollowController { @Resource private IFollowService follow

study_maker的博客 1984

从零搭建芯片设计环境:在Cadence虚拟机中集成QRC进行寄生参数提取

本文详细介绍了在Cadence虚拟机中集成QRC工具进行芯片设计中的寄生参数提取的全流程。从环境准备、QRC安装配置到实际提取操作,提供了完整的步骤指南和常见问题解决方案,帮助工程师高效搭建芯片设计环境并优化提取性能。

weixin_30379531的博客 618

Python实战:用SkillMetrics库5分钟搞定泰勒图绘制(附完整代码)

本文详细介绍了如何使用Python的SkillMetrics库快速绘制专业泰勒图,以直观对比多个模型的预测性能。通过整合相关系数、标准差和中心化均方根误差三个核心指标,该工具能帮助数据科学家和研究者高效完成模型评估与可视化,提升分析报告质量。文章提供了从环境配置、数据准备到高级定制与子图对比的完整代码示例。

7z8x2c4v6b9的博客 371

基于Redis实现Feed流消息推送

feed流即持续更新并呈现给用户内容的信息流。feed是将用户主动订阅的若干消息源组合在一起形成内容聚合器,帮助用户持续地获取最新的订阅源内容。feed直接翻译是饲料的意思,其实是把用户都比喻成爱吃东西得某种动物,不断的给他喂食,满足他的需求,wiki百科上定义是一种数据格式,网站可通过它将最新信息传播给用户,用户能够订阅网站的先决条件是网站可提供持续更新的信息。流,就是他的呈现形式,就是这个信息怎么呈现的,大多数的都是根据时间排列的形式呈现的。

weixin_64161454的博客 726

SAP ABAP BAPI_PRODORD_CHANGE:动态刷新PP主数据的实战解析

本文深入解析了在SAP ABAP开发中,如何利用BAPI_PRODORD_CHANGE函数实现生产订单PP主数据的动态刷新。针对CO02事务码无法满足的后台自动化场景,详细讲解了通过设置explosion_date和explode_new等关键参数来强制重新读取BOM和工艺路线的实战方法,并提供了核心代码示例与避坑指南,确保生产订单信息与最新主数据同步。

weixin_29231027的博客 148

设计一个feed流系统

移动互联网时代,Feed流产品是非常常见的,如朋友圈、微博、抖音等,除此之外,很多App的都会有一个模块,要么叫动态,要么叫消息广场,这些也是Feed流产品。只要大拇指不停地往下划手机屏幕,就有一条条的信息不断涌现出来。就像给宠物喂食一样,只要它吃光了就要不断再往里加,故此得名Feed(饲养)。

zhongzhh8的博客 1989

可信数据空间关键技术和功能架构研究

可信数据空间(TDS)是实现数据安全共享的基础设施,通过数字合约和使用控制技术确保数据跨域流通的可信与安全。其架构包括服务平台和接入连接器,关键技术涵盖访问控制、隐私计算、区块链等。评估重点在于合规性、连接器能力、互联互通及安全体系。核心在于构建规则引擎而非简单数据汇聚,连接器开发比平台建设更重要。当前面临技术成本博弈、跨域身份互认等挑战,需平衡安全、性能与成本,推动数据要素市场发展。

逸尘的专栏 2221

AI智能体在化学中的伦理问题:7个案例,架构师如何应对?

AI在化学中的应用早已不是新鲜事:药物发现中用AI预测分子活性(比如AlphaFold预测蛋白质结构)、化工生产中用AI优化合成路线(降低成本30%+)、材料研发中用AI设计新型电池材料(缩短研发周期5年)……但随着AI从“辅助工具”升级为“自主决策智能体”(比如能自动调整反应条件的“化学机器人”),伦理风险开始从“潜在隐患”变成“真实事故”。AI在化学中会踩哪些伦理“坑”?(用案例具象化)这些“坑”的底层逻辑是什么?(从技术到价值观的链条)架构师能做什么?

AI 算法实战派 1361

Feedly-Fashiolista的feed系统框架学习

django的feed第三方包,有个feedly,是时尚分享网站Fashiolista

AllenLing的专栏 1895

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

Feed系统架构资料收集

完全用nosql轻松打造千万级数据量的微博系统 微博feed系统的push和pull模式和时间分区拉模式架构探讨 关于如何构建一个微博型广播 关于如何构建一个微博型广播2 用 mongodb 储存多态消息/提醒类数据 构建高性能的微博系统-再谈新浪微博架构 人人网技术经理张铁安-Feed系统结构浅析 新浪微博Cache设计@TimYang.pdf新浪微博Cache设计@Tim

张兆坤 9959

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

上一篇: OpenFire简介
下一篇: IaaS, PaaS和SaaS公司都做些什么
dodott
博客等级 码龄22年 60粉丝 26原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值