支撑5亿用户、1.5亿活跃用户的Twitter最新架构详解及相关实现

http://www.csdn.net/article/2013-07-11/2816199-architecture-twitter-uses-to-deal-with-150m-active-usershtml

摘要:Twitter出道之初只是个奋斗在RoR上的小站点,而现在已拥有1.5亿的活跃用户,系统日传输tweet更多达4亿条,并已完成了以服务为核心的系统架构蜕变。后端

Twitter现在在世界范围内已拥有1.5亿的活跃用户,为了给用户生成timeline(时间轴)需支撑30万QPS,其firehose每秒一样生成22MB数据。整个系统天天传输tweet 4亿条,而且只须要5分钟就可让一条tweet从Lady Gaga手中呈现到她3100万粉丝的屏幕上。当下Twitter系统的规模及强大的吞吐量确实惹人艳羡,然而在出道之初Twitter也只是个奋斗在 RoR上的小站点而已,下面就一览Twitter如何完成从RoR到以服务为核心的系统架构蜕变。浏览器

 

Twitter系统的一些特性:缓存

1. 当下的Twitter已不知足于Web Ap的现状。Twitter指望成为一组API,驱动世界范围内的移动客户端,成为世界级最大的实时事件链之一。服务器

2. Twitter主导的是消费机制,而不是生产机制。每秒读取timeline的操做就会产生30万次的查询,而每秒的写入请求只有6000左右。网络

3. 离群值,拥有巨量粉丝的个体开始变得广泛,大量粉丝拥有者发送tweet时会由于大量的扩散而变得缓慢。Twitter试图将这个延时控制在5秒内,可是也并不是一直生效,特别是名人们发送tweet以及相互转发变得愈来愈频繁后。这样就致使转发的内容可能比原始内容先一步到达共同粉丝的界面上,这样一来,就高价值用户来讲,Twitter的主要精力必须从写操做转移到读操做上。架构

4. 使用Redis集群处理Home Timeline(首页时间轴,包含了众多关注者的tweet),最大条数为800。app

5. 从你关注的人和你点击的连接,Twitter能够获知一系列关于你的信息。负载均衡

6. 用户最关心的是tweet内容,然而大部分的基础设施却和这些内容不相关。异步

7. 对如此复杂堆栈进行性能追踪所需求的监视和调试系统每每很是复杂,一样旧决策的影响会不时的出现。

Twitter面临的挑战

1. 1.5亿的用户以及支撑timeline(home及Search)的30万QPS会让最初的具体实现(Naive materialization)变得缓慢。

2. 最初的具体实现由大量选择语句组成,遍布整个Twitter系统,曾今使用后被取缔。

3. 使用一个基于写的扩散方案。在接收到tweet时,系统将作大量的计算以发现tweet须要呈现的用户。这将造就更快、方便的读取,不要对读作任何的计算。因为全部的计算都被安排到写去执行,每秒大约可处理4000个写操做,比读操做要慢一些。

Twitter的团队合做

1. Platform Service团队承担起了Twitter核心基础设施的一切事务:

 

  • 他们负责Timeline Service、Tweet Service、User Service、Social Graph Service这些驱动Twitter平台的全部组件。
  • 内外客户端使用了大体相同的API
  • 产品团队不须要担忧任何规模相关
  • 针对第三方API的注册应用过百万
  • 作容量规划,打造可扩展后端系统架构,在网站超出预期增加时要不断的更换基础设施。

 

2. Twitter还拥有一个架构团队。负责Twitter的总体架构,维护技术负债列表。

Pull和Push模式

1. 任什么时候刻都有用户在Twitter上发布内容,Twitter的任务就是考虑如何将消息同步发出并呈现到粉丝。

2. 真正的挑战就是实时性约束,目标则是在5秒内将消息发送到粉丝:

  • 交付意味着尽量快的收集内容、投入互联网,而且在尽量短的时间内返回。
  • 交付要作的是发布到内存timeline集群、推送通知以及触发电子邮件,其中包括全部的iOS、黑莓、安卓通知以及SMS。
  • Twitter是最大的SMS制造者
  • Elections能够成为产生内容而且以最快速度扩散内容的最大动力

3. 两种类型的timeline:user timeline(用户时间轴,即指定用户tweet页)及home timeline

  • user timeline就是一个指定的用户发布的全部tweet
  • Home timeline是你全部关注用户user timeline的一个临时合并
  • 业务规则。非你关注人@你时,将会被自动过滤,转发的tweet也能够被过滤。
  • 在Twitter的规模作这些事情是很是有挑战性的

 

Pull模式

1. 指向timeline,好比Twitter.com及hone_line API。之因此将tweet发送给你,是由于你对其进行了请求。基于Pull的交付:你经过REST API的调用向Twitter请求这些数据。

2. 查询timeline,搜索API。对资料库进行查询,尽量快的返回全部匹配指定查询的tweet。

Push模式

1. Twitter运行了一个巨型的实时事件系统,经过Firehose以每秒22M的速度推送tweet。

  • 给Twitter打开一个socket,他们将会在150毫秒内完成全部公共tweet的推送。
  • 任什么时候候给推送集群打开的socket都超过1百万个
  • 使用相似搜索引擎的firehose客户端,全部公共的tweet都经过这些socket传输

2. 用户流链接。TweetDeck及Mac版的Twitter一样经过这种方式驱动。在登陆的时候,Twitter会查看你的社交图,一样也只会推送关注人的消息,重建home timeline,而不是在持久的链接过程当中得到同一个timeline。

3. 查询API,发布一个对tweet的持续查询时,每当有新的tweet发布,而且被认定匹配这个查询,系统会将这条tweet发送给相应的socket。

高等级基于Pull的timeline

 

  • Tweet由一个写入API生成,它将会经过负载均衡器及TFE(Twitter Front End)
  • 这种作法很直接,全部的业务逻辑在tweet生成时就已经被执行。
  • 随着tweet的扩散过程开始,新生成的tweet会被投入一个大规模的Redis集群中。每一个tweet都会在3个不一样的机器上作3个拷贝。由于在Twitter的规模,天天会有大把的机器出故障。
  • 粉丝的查询基于Flock的社交图服务,Flock会维护粉丝及粉丝列表:

 

 

  • Flock会返回一个接收者的社交图,而且开始循环访问全部存储在Redis集群上的timeline
  • Redis集群拥有TB级以上的内存
  • 每次投递4K左右的tweet
  • Redis使用原生的表结构
  • 若是你有2万个粉丝,负责粉丝查询的守护进程将会确认2万个用户在Redis集群中的具体位置,而后它会横跨整个Redis集群将Tweet ID插入相应的列表中。因此当你有2万个粉丝时,每条tweet的写入都会形成2万个插入操做。
  • 储存的信息包括新生成tweet的ID、tweet编写者ID以及一个4字节大小的状态信息(转发、评论或者是其它相关)。
  • Home timeline位于Redis集群中,每一个有800条tweet。若是你向后翻太多页就没了,RAM是限制列表tweet数量的最大瓶颈。
  • 为了控制延时,全部活跃用户都存储在内存中。
  • 活跃用户的定义是在30天内有登录过Twitter,固然这个规则能够根据缓存容量、实际使用等进行修改。
  • 若是你不是活跃用户,tweet就不会被放入缓存。
  • 只对home timeline进行存盘(持久化。PS:我的以为这里应该是user timeline,若是是home timeline下文的重建方法显然不科学,欢迎你们讨论
  • 若是home timeline不在Redis集群中,则须要经历一个重建的过程:

 

 

  1. 对社交图服务进行查询,找出你关注的人。分别的访问磁盘获取每一个人的数据,而后将他们送回Redis。
  2. 经过Gizzard使用MySQL处理磁盘存储,这将抽象出全部SQL事务而且提供了全局备份。

 

 

  • 鉴于每条tweet都会作3个备份,若是其中某台机器发生故障,他们无需对这台机器上的全部timeline进行重建。
  • 当tweet被转发时,将会存储一个指向原tweet的指针。

 

 

  • 当作home timeline查询时,Timeline Service将被调用。Timeline Service确认home timeline究竟存在哪台机器上:

 

 

  • 鉴于timeline备份在3个不一样的机器上,因此须要运行3个不一样的哈希环。
  • 一旦找着其中一个,就会尽量快的返回结果。
  • 虽然这个过程会花费稍长的一点时间,可是读的处理仍然很快。从冷缓存到浏览器上呈现大约须要2秒,其中一个API的调用时间大约400毫秒。

 

 

  • 鉴于timeline只包含了tweet的ID,因此还必需要作tweet内容的查询。肯定了ID之后,Twitter将经过T-bird并行获取tweet的内容。
  • Gizmoduck是个用户服务,而Tweetypie则是个tweet对象服务,每一个服务都拥有本身的独立缓存。用户缓存使用的是memcache集群,缓存了全部用户。Tweetypie处理的是上个月的内容,它将一半的tweet储存在它独立的memcache集群中,固然这个部分服务的是内部用户。
  • 内容的过滤一样会省却一些读取时间,好比过滤掉法国的纳粹相关,这些内容的读取时间在呈现以前就被过滤了。

 

高等级的搜索

1. 全部的计算都经过读来解决,这让写更加简洁

2. 当有tweet生成时,Ingester会作相应的语法分析和索引,随后会将其传入Early Bird机器中。Early Bird属于Lucene的修改版本,同时索引都储存在内存中。

3. 在tweet扩散过程当中,它可能会被储存在多个home timeline中,其个数由粉丝的数量决定。然而在Early Bird中,一个tweet只会被存入一个Early Bird机器中(不包括备份)。

4. Blender负责timeline的查询,横跨整个数据中心作集散操做。它对每一个Early Bird作查询,以发现与查询条件匹配的内容。若是你搜索“New York Times”,Blender会查询数据中心的全部分片并返回结果,同时还会作分类、合并及从新排序等。排序的规则基于互动的数据,也就是转发、收藏及评论的数量等。

5. 互动的信息使用写的模式完成,这里会创建一个互动timeline。若是你收藏或者回复一个tweet,将会触发对互动timeline的修改;相似于home timeline,它一样由一系列的互动ID组成,好比收藏ID、评论ID等等。

6. 全部这些信息都被送到Blender。以读的方式进行重算、合并以及分类,返回的结果就是search timeline为你呈现的界面。

7. Discovery是个基于你相关信息的定制搜索,这些信息主要来自你关注的人、打开的连接,而从新排序的规则一样基于这些信息。

Search和Pull是相反的

1. 搜索和pull看起来很是类似,其实他们有着本质上的区别。

2. 在home timeline状况下:

  • 写。一个写tweet的动做会触发一个O(n)规模的Redis集群写入操做,n的值取决于粉丝的数量,因而可知处理Lady Gaga及Barack Obama这样拥有数千万粉丝的名人将会很麻烦。Redis集群上的信息都会写入磁盘,Flock集群会将user timeline储存到磁盘上,可是一般状况下timeline在Redis集群的内存中均可以发现。
  • 读。经过API或网络查找Redis是一个常数规模的操做。Twitter对home tiimeline的读操做作了高可用性优化,读操做只花费数十毫秒。这里也能够看出Twitter主导的是一个消费机制,而不是生产机制。每秒可处理30万个读操做,而写操做每秒处理6000个。

3. 搜索timeline状况:

  • 写。Tweet生成,而且传输到Ingester,只会写入一个Early Bird机器。一个tweet处理的时间大约为5秒,其中包括了排队及寻找待写入的Early Bird 机器。
  • 读。每一个读请求都会触发一个O(n)规模的集群读操做。读大约须要100毫秒,搜索不涉及到存盘。全部的Lucene索引都保存在RAM中,因此聚散是很是有效率的,由于不涉及到磁盘。

4. Tweet的内容基本上与大多数的基础设施都是无关的。T-bird存储了全部tweet内容,大部分的tweet内容都是在内存中。若是没有的话,能够经过select查询将其拉回内存。与tweet内容相关的功能很是少,搜索就是其中一个,而Home timeline则彻底不关心。

将来的工做

1. 如何将这条数据的管道打造的更快更有效

2. 在5秒内作到tweet的扩散,可是并非时刻的奏效,特别是愈来愈多的高粉单位。

3. Twitter是非对称的关注,只有你关注人的tweet才会呈现给你。Twitter能够从这些单向关注中获取你更多的信息,有些单向关注一样还影射出一些社会契约。

4. 问题通常发生在大基数的图上:@ladygaga拥有3100万粉丝,@katyperry拥有2800万粉丝,@justinbieber拥有2800万粉丝,@barackobama拥有2300万粉丝。

5. 大批量粉丝的拥有者每发送一条tweet将形成数据中心大量的写入操做,而随着愈来愈多名人之间的交互,挑战变得更加的艰巨。

6. 这些须要扩散给大批量用户的tweet是Twitter最大的挑战,在关注这些名人的共同粉丝中,常常会出现回复tweet比原文更早一步送达的状况。他们在站点中引入竞态条件,好比最近关注Lady Gaga的粉丝可能会比老早以前关注的粉丝早5分钟看到tweet内容。好比说一个用户先收到了tweet,并进行回复,然而这时候Lady Gaga的原微博并无扩散完毕,这样就会存在有些用户先看到回复的状况,为用户形成很大的困扰。Tweet经过ID进行排序,由于他们大多数是单调递增的,然而在如此粉丝规模下,这种作法并不奏效。

7. 寻找读和写途径的合并,再也不作如此大规模的扩散;好比传播Taylor Swift新生成的tweet,取代在生成时进行扩散tweet ID,而是在读取时候就进行合并。经过平衡读写途径,节省百分之几十的资源。

解耦相关

1. 基于Twitter经过各类途径传播tweet,解耦可让不一样技术团队独立完成本身的工做。

2. 基于性能问题,系统也须要解耦。Twitter过去使用的一直是彻底同步模式,而在两年前由于性能问题他们停用了这个模式。设备接收一个tweet须要145毫秒,接收完毕后就断开全部客户端链接,这么作一样也由于技术负债。写的路径由Ruby驱动,经过MRI实现,一个单线程服务器,每次Unicorn worker分配都会耗尽全部处理性能。每当有tweet流入,Ruby就会接收它,将它放到一个队列中而后断开连接。他们在每台服务器上只运行45-48个进程,这样的话每一个机箱能同时处理的tweet数量也是这么多,因此他们必须尽量快的断开链接。

3. 当下的tweet已经经过异步模式来处理,而这些讨论也都是创建在异步之上。

监视相关

1. 系统性能实时仪表盘

2. 使用VIZ系统监视每一个集群,请求Timeline Service并从Scala集群获取数据的平均时间为5毫秒。

3. 基于Google Dapper系统的Zipkin,工程师能够经过Zipkin对请求的细节进行监视,好比获取请求所访问的服务及请求时间,这样就能够获知每一个请求的性能细节。这样就能够经过每一个阶段耗费的时间对系统进行调试,一样也能够从整体上看从请求到交付耗费的时间。花费了两年的时间,Twitter将活跃用户的timeline降到2毫秒。

部分统计数据:

 

  • 若是你有100万个粉丝,每一个tweet将耗费数秒的时间来传播
  • Tweet输入统计:天天4亿条;日平均统计5000每秒;日统计峰值7000每秒;大事件期间高于1.2万每秒。
  • Timeline交付统计:天天300亿次(更多数据见原文)

 

原文连接: The Architecture Twitter Uses to Deal with 150M Active Users, 300K QPS, a 22 MB/S Firehose, and Send Tweets in Under 5 Seconds  (编译/仲浩 审校/周小璐)

欢迎关注 @CSDN云计算微博,了解更多云信息。 

相关文章
相关标签/搜索