编者注:本文为历史博文归档,主要反映 Twitter 早期(约 2011 年前后)的架构设计。文中涉及的 JDK、框架与工具链版本请以当前官方文档为准。部分引用外链图片可能失效,阅读时请注意时效性。

Twitter 网站架构学习笔记

作为 140 字符限制的缔造者,Twitter 既简单又复杂。简单在于,仅用 140 个字符便使数次世界性事件的传播速度超越了任何媒体;复杂在于,要为数亿用户提供这看似简单的服务,背后的架构挑战巨大。正所谓“因为简单,所以复杂”。本文将对 Twitter 网站架构的学习体会与大家分享。

一、Twitter 网站基本情况概览

截至 2011 年 4 月,Twitter 的注册用户约为 1.75 亿,并以每天 30 万的新用户注册数增长。但其真正的活跃用户远小于这个数目,大部分注册用户没有关注者或未关注他人,这也是其与 Facebook 当时 6 亿活跃用户不能相提并论的原因。

主要运营数据如下:

  • 独立访问用户数:每月约 180 万,其中 75% 的流量来自 Twitter.com 以外的网站。
  • API 请求:每天通过 API 产生约 30 亿次请求。
  • Tweet 产生量:每天平均产生约 5500 万次 Tweet。
  • 用户终端:37% 的活跃用户为手机用户。
  • 来源分布:约 60% 的 Tweet 来自第三方应用。

技术栈平台

Ruby on RailsErlangMySQLMongrelMuninNagiosGoogle AnalyticsAWStatsMemcached

下图是 Twitter 的整体架构设计图:

Twitter 整体架构设计图

二、Twitter 的平台组成

Twitter 平台大致由 Twitter.com 官网、手机客户端以及第三方应用构成,如下图所示:

Twitter 平台组成

其中,流量主要以手机和第三方应用为主要来源。以下是核心组件的技术选型与说明:

  • Ruby on Rails:Web 应用程序框架。
  • Erlang:通用的面向并发的编程语言。开源项目地址:http://www.erlang.org/
  • AWStats:实时日志分析系统。开源项目地址:http://awstats.sourceforge.net/
  • Memcached:分布式内存缓存组件。
  • Starling:Ruby 开发的轻量级消息队列。
  • Varnish:高性能开源 HTTP 加速器。
  • Kestrel:Scala 编写的消息中间件。开源项目地址:http://github.com/robey/kestrel
  • Comet Server:Comet 是一种 Ajax 长连接技术,利用 Comet 可以实现服务器主动向 Web 浏览器推送数据,从而避免客户端轮询带来的性能损失。
  • libmemcached:一个 Memcached 客户端库。
  • MySQL:关系型数据库服务器。
  • Mongrel:Ruby 的 HTTP 服务器,专门应用于 Rails。开源项目地址:http://rubyforge.org/projects/mongrel/
  • Munin:服务端监控程序。项目地址:http://munin-monitoring.org/
  • Nagios:网络监控系统。项目地址:http://www.nagios.org/

三、缓存架构

缓存在大型 Web 项目中起到了举足轻重的作用,毕竟数据越靠近 CPU 存取速度越快。下图是 Twitter 的缓存架构图:

Twitter 缓存架构图

大量使用 Memcached 作缓存

  • 计数优化:例如,如果获得一个 count 非常慢,可以将 count 在 1 毫秒内写入 Memcached。
  • 朋友状态:获取朋友的状态涉及安全等复杂问题,因此朋友状态更新后直接写入缓存而不是查询数据库,避免接触数据库层。
  • ActiveRecord 对象:由于对象很大所以没有被整体缓存。Twitter 将 critical 的属性存储在一个哈希(Hash)里,并且在访问时进行迟加载(Lazy Load)。
  • API 请求缓存:90% 的请求为 API 请求,所以在前端不做任何 Page 和 Fragment 缓存。页面非常时间敏感,直接缓存效率不高,但 Twitter 缓存了 API 请求。

Memcached 缓存策略改进

在 Memcached 缓存策略中,Twitter 做了如下改进:

  1. 直写式向量缓存(Vector Cache):包含了一个 Tweet ID 的数组,Tweet ID 是序列化的 64 位整数,命中率是 99%。
  2. 直写式行缓存(Row Cache):包含了数据库记录(用户和 Tweets)。这一缓存有着 95% 的命中率。
  3. 直读式碎片缓存(Fragment Cache):包含了通过 API 客户端访问到的 Tweets 序列化版本,这些 Tweets 可以被打包成 JSON、XML 或者 Atom 格式,同样也有着 95% 的命中率。
  4. 页面缓存池(Page Cache):为页面缓存创建一个单独的缓存池。该页面缓存池使用了一个分代的键模式,而不是直接的失效策略。

四、消息队列

Twitter 大量使用消息队列。生产者生产消息并放入队列,然后分发给消费者。Twitter 主要的功能是作为不同形式(SMS、Web、IM 等等)之间的消息桥接。

消息队列技术的演进历程如下:

  • DRb (Distributed Ruby):意味着分布式 Ruby。有一个库允许你通过 TCP/IP 从远程 Ruby 对象发送和接收消息,但是它有点脆弱。
  • Rinda:它是使用 tuplespace 模型的一个共享队列,但是队列是持久的,当失败时消息会丢失。
  • Erlang:曾尝试使用 Erlang 处理并发。
  • Starling:最终移到 Starling,用 Ruby 写的一个分布式队列。

分布式队列通过将它们写入硬盘用来挽救系统崩溃,其他大型网站也使用这种简单的方式。


原文链接http://www.itivy.com/ivy/archive/2011/8/14/the-architecture-of-twitter.html

说明:本文内容基于 2011 年左右的技术资料整理,部分数据(如用户量、Tweet 产量)及技术选型(如 Starling、Mongrel)可能已随 Twitter 架构演进发生变化(例如后续迁移至 Scala、Java 及自研中间件等),仅供架构学习参考。