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

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

对于许多大型的创业公司,如Pinterest、Instagram、Wanelo和Fashiolista来说,feed是一个核心组件。在Fashiolista网上的 flat feedaggregated feednotification系统功能都是靠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

通过比较HBaseDynamoDBCassandra2.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的生态系统正在发生巨变,CQLEnginePython-Driver都是很优秀的项目,但是它们需要投入一定的时间去学习。

结论

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

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

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

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

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

百万用户时尚分享网站feed系统扩展实践的更多相关文章

  1. Feed系统架构资料收集

    完全用nosql轻松打造千万级数据量的微博系统 微博feed系统的push和pull模式和时间分区拉模式架构探讨 关于如何构建一个微博型广播 关于如何构建一个微博型广播2 用 mongodb 储存多态 ...

  2. Feed系统架构资料收集(转)

    add by zhj:有些链接已经失效,后续会修改. 原文:http://blog.csdn.net/zhangzhaokun/article/details/7834797 完全用nosql轻松打造 ...

  3. Feed系统设计分析(类似微博的用户动态分享问题)

    Feed系统 最近在研究一个个人动态分享平台,对动态的推送方式有些疑惑,于是研究到了以下结果. 简介 在信息学里面,Feed其实是一个信息单元,比如一条朋友圈状态.一条微博.一条资讯或一条短视频等,所 ...

  4. ASP.NET MVC 实现页落网资源分享网站+充值管理+后台管理(7)之扩展基类和区域创建以及文本编辑配置

    一.扩展基类和区域创建 (1)在应用之前,我们先在表现层创建一个公共的系统扩展文件来(SystemExtension)存放我们需要延伸和扩展的方法类. 在常规的项目系统操作中,我们都需要用到增删查改的 ...

  5. php + Redis 写的类似于新浪微博的feed系统

    最近接了一个feed系统的外包,类似于微博那种!客户端是ios和android,服务器用的php,数据库用的是redis.分享下服务器和数据库部分的功能!希望对大家有帮助. 关于redis的介绍,大家 ...

  6. 我用爬虫一天时间“偷了”知乎一百万用户,只为证明PHP是世界上最好的语言

    我用爬虫一天时间“偷了”知乎一百万用户,只为证明PHP是世界上最好的语言 2015-08-06 猿圈 我用爬虫一天时间“偷了”知乎一百万用户 只为证明PHP是世界上最好的语言 看了不少朋友圈里推荐的P ...

  7. ArcGIS最权威、最专业的技术分享网站:积思园(www.iarcgis.com)

    你对iArcGIS.com说点什么 为什么会有该网站的产生 在这个所谓的“大数据”的时代,每个人都深陷于海量信息无法自拔,因为过多碎片化的数据只会让自己的思维更加迷离,快餐式的阅读只会让自己变得虚胖. ...

  8. 微信团队原创分享:iOS版微信的内存监控系统技术实践

    本文来自微信开发团队yangyang的技术分享. 一.前言 FOOM(Foreground Out Of Memory),是指App在前台因消耗内存过多引起系统强杀.对用户而言,表现跟crash一样. ...

  9. Ouibounce – 在用户离开你网站时显示模态弹窗

    Ouibounce 是一个微小的库,用于实现在用户离开你的网站的时候显示一个模式窗口.这个库可以帮助你增加着陆页的转换率. Ouibounce 会在当鼠标光标移动到接近(或通过)视口(viewport ...

随机推荐

  1. The C Programming Language (second edition) 实践代码(置于此以作备份)

    1. #include <stdio.h> #include <stdlib.h> #include <math.h> #include<time.h> ...

  2. hdu 1048 The Hardest Problem Ever

    import java.util.Arrays; import java.util.Scanner; public class Main { public static void main(Strin ...

  3. Unity自动打包Apk

    unity打包apk相对来说比较容易,相信出过的人都明白,出包过程,没有大的难度,一步一操作,一步一等待,繁琐耗时,不懂的人又代替不了.这时候需求就来了,如何简单的一键打包搞定,这个就稍微有点难度,当 ...

  4. linux 多线程 LinuxThreads(转)

    Linux 线程实现机制分析 http://www.ibm.com/developerworks/cn/linux/kernel/l-thread/ 上面文章分析的非常透彻 按照教科书上的定义,进程是 ...

  5. apache安装后编译新模块

    1.下载对应版本的源码包 2.解压后找到modules/mappers目录并进入 3.运行如下命令自动编译.安装和修改httpd.conf文件: /usr/sbin/apxs -c -i -a mod ...

  6. CentOS 6.6编译安装Nginx1.6.2+MySQL5.6.21+PHP5.6.3(转)

    vi /etc/sysconfig/iptables #编辑防火墙配置文件 # Firewall configuration written by system-config-firewall # M ...

  7. IHttpModule在webconfig中的注册

    在asp.net中,提供了两种方式用来解决获取由asp.net服务器创建和维护的HttpApplication对象,方便注册HttpApplication对象的事件处理.这两种方式为:IHtpModu ...

  8. CrtCtl (客户端认证的证书、私钥)的控制

    crt (证书文件) 编辑 本词条缺少名片图,补充相关内容使词条更完整,还能快速升级,赶紧来编辑吧! 客户端认证的证书.私钥. 中文名 crt 性    质 证书文件 类    型 客户端认证的证书. ...

  9. javascript和HTML5上传图片之前实现预览效果

    一:FileList对象与file对象 FileList对象表示用户选择的文件列表,在HTML4中,file控件内只允许放置一个文件,但是到了HTML5中,通过添加multiple属性,file控件内 ...

  10. 常用工具和API的网站收集

    1.小图标在线查找 https://www.iconfinder.com/ 2.在线做图,Flowchart流程图,BPMN图,Org组织结构图等 http://www.processon.com/ ...