Twitter系统架构参考

Push、Pull模式

  • 每时每刻都有用户在Twitter上发表内容,Twitter工作是规划如何组织内容并把它发送用户的粉丝。
  • 实时是真正的挑战,5秒内将消息呈现给粉丝是现阶段的目标。
    • 投递意味着内容、投入互联网,然后尽可能快的发送接收。
    • 投递将历时数据放入存储栈,推送通知,触发电子邮件,iOS、黑莓及Android手机都能被通知到,还有短信。
    • Twitter是世界上活跃中最大的信息发送机。
    • 推荐是内容产生并快速传播的巨大动力。
  • 两种主要的时间轴:用户的及主页的。
    • 用户的时间轴特定用户发送的内容。
    • 主页时间表是一段时间内所有你关注用户发布的内容。
    • 线上规则是这样的:@别人是若被@的人你未关注的话将被隔离出来,回复一个转发可以被过滤掉。
    • 这样在Twitter对系统是个挑战。
  • Pull模式
    • 有针对性的时间轴。像http://twitter.com主页和home_timeline的API。你请求它才会得到数据。拉请求的不少:通过REST API请求从Twitter获取数据。
    • 查询时间轴,搜索的API。查询并尽可能快的返回所有匹配的推特。
  • Push模式
    • Twitter运行着一个最大的实时事件系统,出口带宽22MB/秒。
      • 和Twitter建立一个连接,它将把150毫秒内的所有消息推送给你。
      • 几乎任何时候,Push服务簇上大约有一百万个连接。
      • 像搜索一样往出口发送,所有公共消息都通过这种方式发送。
      • 不,你搞不定。(实际上处理不了那么多)
    • 用户流连接。 TweetDeck 和Twitter的Mac版都经过这里。登录的时,Twitter会查看你的社交图,只会推送那些你关注的人的消息,重建主页时间轴,而不是在持久的连接过程中使用同一个时间轴 。
    • 查询API,Twitter收到持续查询时,如果有新的推特发布并且符合查询条件,系统才会将这条推特发给相应的连接。

Twitter架构


twiterarchitect

时间轴

  • 短消息(Tweet)通过一个写API传递进来。通过负载平衡以及一个TFE(短消息前段),以及一些其它的没有被提到的设施。
  • 这是一条非常直接的路径。完全预先计算主页的时间轴。所有的业务逻辑在短消息进入的时候就已经被执行了。
  • 紧接着扇出(向外发送短消息)过程开始处理。进来的短消息被放置到大量的Redis集群上面。每个短息下在三个不同的机器上被复制3份。在Twitter 每天有大量的机器故障发生。
  • 扇出查询基于Flock的社交图服务。Flock 维护着关注和被关注列表。
  • Flock 返回一个社交图给接受者,接着开始遍历所有存储在Redis 集群中的时间轴。
  • Redis 集群拥有若干T的内存。
  • 同时连接4K的目的地。
  • Redis 中使用原生的链表结构
  • 假设你发出一条短消息,并且你有20K个粉丝。扇出后台进程要做的就是在Redis 集群中找出这20K用户的位置。接着它开始将短消息的ID 注入到所有这些列表中。因此对于每次写一个短消息,都有跨整个Redis集群的20K次的写入操作。
  • 存储的是短消息的ID, 最初短消息的用户ID, 以及4个字节,标识这条短消息是重发还是回复还是其它什么东东。
  • 你的主页的时间轴驻扎在Redis集群中,有800条记录长。如果你向后翻很多页,你将会达到上限。内存是限制资源决定你当前的短消息集合可以多长。
  • 每个活跃用户都存储在内存中,用于降低延迟。
  • 活跃用户是在最近30天内登陆的twitter用户,这个标准会根据twitter的缓存的使用情况而改变。
  • 只有你主页的时间轴会存储到磁盘上。
  • 如果你在Redis 集群上失败了,你将会进入一个叫做重新构建的流程。
  • 新社交图服务。找出你关注的人。对每一个人查询磁盘,将它们放入Redis中
  • MySQL通过Gizzard 处理磁盘存储,Gizzard 将SQL事务抽象出来,提供了全局复制。

middleware

  • 通过复制3次,当一台机器遇到问题,不需要在每个数据中心重新构建那台机器上的时间轴。
  • 如果一条短消息是另外一条的转发,那么一个指向原始短消息的指针将会存储下来。
  • 当你查询你主页的时间轴时候,时间轴服务将会被查询。时间轴服务只会找到一台你的时间轴所在的机器。
  • 高效的运行3个不同的哈希环,因为你的时间轴存储在3个地方
  • 它们找到最快的第一个,并且以最快速度返回。
  • 需要做的妥协就是,扇出将会花费更多的时间,但是读取流程很快。大概从冷缓存到浏览器有2秒种时间。对于一个API调用,大概400ms。
  • 因为时间轴只包含短消息ID, 它们必须”合成”这些短消息,找到这些短消息的文本。因为一组ID可以做一个多重获取,可以并行地从T-bird 中获取短消息。
  • Gizmoduck 是用户服务,Tweetypie 是短消息对象服务。每个服务都有自己的缓存。用户缓存是一个memcache集群 拥有所有用户的基础信息。Tweetypie将大概最近一个半月的短消息存储在memcache集群中。这些暴露给内部的用户。
  • 在边界将会有一些读时过滤。例如,在法国过滤掉纳粹内容,因此在发送之前,有读时内容剥离工作。

搜索

  • 与Pull相反,所有计算都在读时执行,这样可以使写更简单。
  • 产生一条推特时,Ingester会对其做语法分析找出新建索引的一切东西,然后将其传入一台Early Bird机器。Early Bird是Lucene的修改版本,索引储存在内存中。
  • 在推特的分发过程中可能被储存在多个由粉丝数量决定的主页时间轴中,一条推特只会存入一个Early Bird机器中(不包括备份)。
  • Blender进行时间轴的跨数据中心集散查询。为发现与查询条件匹配的内容它查询每个Early Bird。如果你搜索“纽约时报”,所有分片将被查询,结果返回后还会做分类、合并及重排序等。排序是基于社会化度量的,这些度量基于转发、收藏及评论的数量等。
  • 互动信息是在写上完成的,这里会建立一个互动时间轴。当收藏或回复一条推特时会触发对互动时间轴的修改,类似于主页时间轴,它是一系列的活跃的ID,有最受喜欢的ID,新回复ID等。
  • 所有这些都被送到Blender,在读路径上进行重计算、合并及分类,返回的结果就是搜索时间轴上看到的东西
  • Discovery是基于你相关信息的定制搜索,Twitter通过你关注的人、打开的链接了解你的信息,这些信息被应用在Discovery搜索上,重新排序也基于这些信息。

Search和Pull是相反的

  • Search和Pull明显的看起来很相似,但是他们在某些属性上却是相反的。
  • 在home timeline时:
    • 写操作。tweet写操作引发O(n)个进程写入Redis集群,n代表你的粉丝,如果是这样,处理Lady Gaga或是Obama百万粉丝的数据就得用10s的时间,那是很难接受的。所有的Redis集群都支持硬盘处理数据,但是一般都是在RAM里操作的。
    • 读操作。通过API或是网络可用O(1)的时间来找到Redis机器。Twitter在寻找主页路径方面做了大量的优化。读操作可在10毫秒完成。所有说Twitter主导消费机制而不是生产机制。每秒可处理30万个请求和6000 RPS写操作。
  • 在搜索timeline时:
    • 写操作。一个tweet请求由Ingester收到并有一个Early Bird机器来处理。写操作时O(1).一个tweet需要5秒的处理时间,其包括排队等待和寻找路径。
    • 读操作。读操作引发O(n)个集群读操作。大多数人不用search,这样他们可以在存储tweets上面更加有效,但是他们得花时间。读需要100毫秒,search不涉及硬盘操作。全部Lucene 索引表都放入RAM,这样比放在硬盘更加有效。
  • tweet的内容和基础设施几乎没什么关系。T-bird stores负责tweet所有的东西。大多数tweet内容是放在RAM处理的。如有没再内存中,就用select query将内容抓到内存中。只有在search,Trends,或是What’s Happening pipelines中涉及到内容,hone timeline对此毫不关心。

展望:

      当这些人中有人发微博的时候,数据中心需要写大量微薄到各个关注者。当他们开始聊天时候,这是非常大的挑战,而这时刻都在发生着。

  • 这些高关注度的Fanout用户是Twitter最大的挑战。在名人原始微薄发出到关注用户之前,回复一直可以看到。这导致整个网站紊乱。Lady Gaga的一条微薄到关注用户需要几分钟的时间,所以关注者看到这条微薄时间是在不同时间点上。有些人可能需要大概5分钟的时间才能看到这条微薄,这远远落后于其他人。可能早期收到微薄的用户已经收到了回复的列表,而这时候回复还正在处理之中,而fanout还一直进行着所以回复被加了进来。这都发生在延迟关注者收到原始微薄之前。这会导致大量用户混乱。微薄发出之前是通过ID排序的,这导致它们主要是单调增长地,但是那种规模下这不能解决问题。对高值的fanouts队列一直在备份。
  • 试图找到解决合并读和写路径的方法。不在分发高关注度用户微薄。对诸如Taylor Swift的人不会在额外的处理,只需要在读时候,他的时间点并入即可。平衡读和写的路径。可以节约百分之10s的计算资源。

解耦

  • Tweet通过很多的方式解除关联,主要地通过彼此解耦的方式。搜索、推送、邮件兴趣组以及主页时间轴可以彼此独立的工作。
  • F由于性能的原因,系统曾经被解耦过。Twitter曾经是完全同步地方式的,由于性能的原因2年前停止了。提取一个tweet到tweet接口需要花费145微秒,接着所有客户端被断开连接。这是历史遗留的问题。写路径是通过MRI用一个Ruby驱动的程序,一个单线程的服务。每次一个独立的woker被分配的时候,处理器都会被耗尽。他们希望有能力尽可能快的去释放客户端连接。一个tweet进来了。Ruby处理了它。把它插入队列,并且断开连接。他们仅仅运行大概45-48进程/盒。所以他们只能并行处理同样多tweets/盒,所以他们希望尽可能快的断开连接。
  • Tweets 被切换到异步路径方式,我们讨论所有东西都被剔除了。

监控

  • 办公室四处的仪表盘显示了系统在任何给定时间系统的运行状态。
  • 如果你有100万的关注者,将会要花费好几分钟到分发到所有tweets。
  • Tweets 入口统计:每天400兆的tweets。日平均每秒种5000;日高峰时每秒7000;有事件时候是每秒超过12000。
  • 时间轴分发统计:30b分发/日(约21M/分钟);3.5秒@p50(50%分发率)分发到1M;300k 分发/秒;@p99 大概需要5分钟。
  • 一个名为VIZ的监控系统监控各个集群。时间轴服务检索数据集群数据的平均请求时间是5毫秒。@p99需要100毫秒。@p99.9需要请求磁盘,所以需要大概好几百毫秒。
  • Zipkin 是基于谷歌Dapper的系统。利用它可以探测一个请求,查看他点击的每一个服务,以及请求时间,所以可以获得每个请求的每一部分性能细节信息。你还还可以向下钻取,得到不同时间周期下的每单个的请求的详细信息。大部分的时间是在调试系统,查看请求时间都消耗的什么地方。它也可以展示不同纬度的聚合统计,例如,用来查看fanout和分发了多久。大概用了2年长的一个工程,来把活跃用户时间线降到2毫秒。大部分时间用来克服GC停顿,memchache查询,理解数据中心的拓扑应该是怎么样结构,最后建立这种类型集群。




今天先到这儿,希望对云原生,技术领导力, 企业管理,系统架构设计与评估,团队管理, 项目管理, 产品管管,团队建设 有参考作用 , 您可能感兴趣的文章:
领导人怎样带领好团队
构建创业公司突击小团队
国际化环境下系统架构演化
微服务架构设计
视频直播平台的系统架构演化
微服务与Docker介绍
Docker与CI持续集成/CD
互联网电商购物车架构演变案例
互联网业务场景下消息队列架构
互联网高效研发团队管理演进之一
消息系统架构设计演进
互联网电商搜索架构演化之一
企业信息化与软件工程的迷思
企业项目化管理介绍
软件项目成功之要素
人际沟通风格介绍一
精益IT组织与分享式领导
学习型组织与企业
企业创新文化与等级观念
组织目标与个人目标
初创公司人才招聘与管理
人才公司环境与企业文化
企业文化、团队文化与知识共享
高效能的团队建设
项目管理沟通计划
构建高效的研发与自动化运维
某大型电商云平台实践
互联网数据库架构设计思路
IT基础架构规划方案一(网络系统规划)
餐饮行业解决方案之客户分析流程
餐饮行业解决方案之采购战略制定与实施流程
餐饮行业解决方案之业务设计流程
供应链需求调研CheckList
企业应用之性能实时度量系统演变

如有想了解更多软件设计与架构, 系统IT,企业信息化, 团队管理 资讯,请关注我的微信订阅号:

MegadotnetMicroMsg_thumb1_thumb1_thu[2]

作者:Petter Liu
出处:http://www.cnblogs.com/wintersun/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。 该文章也同时发布在我的独立博客中-Petter Liu Blog。

posted on 2022-07-16 09:03  PetterLiu  阅读(1145)  评论(0编辑  收藏  举报