[Architecture]tumblr.com

 

http://www.tumblr.com/

 

# Challenges

    页面访问量: 每天5亿次PV()

    峰值请求每秒近4万次

    每天超过1TB数据进入Hadoop集群

    MySQL/HBase/Redis/memcache每天生成若干TB数据

 

# Software

    OS X  for Development ;  Linux(CentOS/Scientific) for Production

    Apache Varnish, HAProxy, nginx

    PHP, Scala, Ruby

    Redis, HBase, MySQL

    memcache, Gearman, Kafka, Kestrel, Finagle

    Thrift, HTTP

    Func (安全、支持脚本的远程控制框架和API, http://func.et.redhat.com/)

    Git, Capistrano(多服务器脚本部署工具), Puppet, Jenkins

 

# Hardware

    500台Web服务器

    200台数据库服务器(47 pool,20 shard)

    30台memcache服务器

    22台Redis服务器

    15台Varnish服务器

    25台HAproxy节点

    8台nginx服务器

    14台工作队列服务器(Kestrel + Gearman)

 

# 老的架构

Tumblr最开始托管在Rackspace,每个自定义域名的博客都有一个A记录。当2007年Rackspace无法满足其发展速度不得 不迁移时,大量的用户都需要同时迁移。所以他们不得不将自定义域名保留在Rackspace,然后再使用HAProxy和Varnish路由到新的数据中 心。类似这样的遗留问题很多。

开始的架构演进是典型的LAMP路线:

最初用PHP开发,几乎所有程序员都用PHP

最初是三台服务器:一台Web,一台数据库,一台PHP

为了扩展,开始使用memcache,然后引入前端cache,然后在cache前再加HAProxy,然后是MySQL sharding(非常奏效)

采用“在单台服务器上榨出一切”的方式。过去一年已经用C开发了两个后端服务:ID生成程序Staircar(用Redis支持Dashboard通知)

Dashboard采用了“扩散-收集”方式。当用户访问Dashboard时将显示事件,来自所关注的用户的事件是通过拉然后显示的。这样支撑了6个月。由于数据是按时间排序的,因此sharding模式不太管用。

 

# 新的架构

新的架构从LAMP改为以JVM为中心,选用了Scala和Finagle:

    Finagle是选择Scala的重要因素之一。这个来自Twitter的库可以解决大多数分布式问题,比如分布式跟踪、服务发现、服务注册等。

    转到JVM上之后,Finagle提供了团队所需的所有基本功能(Thrift, ZooKeeper等),无需再开发许多网络代码,另外,团队成员认识该项目的一些开发者。

    Foursquare和Twitter都在用Finagle,Meetup也在用Scala。

    应用接口与Thrift类似,性能极佳。

    团队本来很喜欢Netty,但不想用Java,Scala是不错的选择。

之所以没有选择Node.js,是因为以JVM为基础更容易扩展。Node的发展为时尚短,缺乏标准、最佳实践 以及大量久经测试的代码。而用Scala的话,可以使用所有Java代码。虽然其中并没有多少可扩展的东西,也无法解决5毫秒响应时间、49秒HA、4万 每秒请求甚至有时每秒40万次请求的问题。但是,Java的生态链要大得多,有很多资源可以利用。

内部服务从C/libevent为基础正在转向Scala/Finagle为基础。

开始采用新的NoSQL存储方案如HBase和Redis。但大量数据仍然存储在大量分区的MySQL架构中, 并没有用HBase代替MySQL。HBase主要支持短地址生产程序(数以十亿计)还有历史数据和分析,非常结实。此外,HBase也用于高写入需求场 景,比如Dashboard刷新时一秒上百万的写入。之所以还没有替换HBase,是因为不能冒业务上风险,目前还是依靠人来负责更保险,先在一些小的、 不那么关键的项目中应用,以获得经验。MySQL和时间序列数据sharding(分片)的问题在于,总有一个分片太热。另外,由于要在slave上插入 并发,也会遇到读复制延迟问题。

 

此外,还开发了一个公用服务框架:

    花了很多时间解决分布式系统管理这个运维问题。

    为服务开发了一种Rails scaffolding,内部用模板来启动服务。

    所有服务从运维的角度来看都是一样的,所有服务检查统计数据、监控、启动和停止的方式都一样。

   工具方面,构建过程围绕SBT(一个Scala构建工具),使用插件和辅助程序管理常见操作,包括在Git里打标签,发布到代码库等等。大多数程序员都不用再操心构建系统的细节了。

200台数据库服务器中,很多是为了提高可用性而设,使用的是常规硬件,但MTBF(平均故障间隔时间)极低。故障时,备用充足。

为了支持PHP应用有6个后端服务,并有一个小组专门开发后端服务。新服务的发布需要两到三周,包括 Dashboard通知、Dashboard二级索引、短地址生成、处理透明分片的memcache代理。其中在MySQL分片上耗时很多。虽然在纽约本 地非常热,但并没有使用MongoDB,他们认为MySQL的可扩展性足够了。

Gearman用于会长期运行无需人工干预的工作。

可用性是以达到范围(reach)衡量的。用户能够访问自定义域或者Dashboard吗?也会用错误率。

历史上总是解决那些最高优先级的问题,而现在会对故障模式系统地分析和解决,目的是从用户和应用的角度来定成功指标。(后一句原文似乎不全)

最开始Finagle是用于Actor模型的,但是后来放弃了。对于运行后无需人工干预的工作,使用任务队列。而且Twitter的util工具库中有Future实现,服务都是用Future(Scala中的无参数函数,在与函数关联的并行操作没有完成时,会阻塞调用方)实现的。当需要线程池的时候,就将Future传入Future池。一切都提交到Future池进行异步执行。

Scala提倡无共享状态。由于已经在Twitter生产环境中经过测试,Finagle这方面应该是没有问题的。使用Scala和Finagle 中的结构需要避免可变状态,不使用长期运行的状态机。状态从数据库中拉出、使用再写回数据库。这样做的好处是,开发人员不需要操心线程和锁。

22台Redis服务器,每台的都有8-32个实例,因此线上同时使用了100多个Redis实例。

Redis主要用于Dashboard通知的后端存储。

所谓通知就是指某个用户like了某篇文章这样的事件。通知会在用户的Dashboard中显示,告诉他其他用户对其内容做了哪些操作。

高写入率使MySQL无法应对。

通知转瞬即逝,所以即使遗漏也不会有严重问题,因此Redis是这一场景的合适选择。

这也给了开发团队了解Redis的机会。

使用中完全没有发现Redis有任何问题,社区也非常棒。

开发了一个基于Scala Futures的Redis接口,该功能现在已经并入了Cell架构。

短地址生成程序使用Redis作为一级Cache,HBase作为永久存储。

Dashboard的二级索引是以Redis为基础开发的。

Redis还用作Gearman的持久存储层,使用Finagle开发的memcache代理。

正在缓慢地从memcache转向Redis。希望最终只用一个cache服务。性能上Redis与memcache相当。

 

# References

[51CTO] (http://os.51cto.com/art/201202/317899.htm)

[High Scalability] (http://highscalability.com/blog/2012/2/13/tumblr-architecture-15-billion-page-views-a-month-and-harder.html)

 

posted on 2012-09-17 23:07  飘行天下  阅读(1054)  评论(0编辑  收藏  举报

导航