IT技术博客大学习 共学习 共进步

Twitter“鲸鱼”故障技术剖析

Tim[后端技术] 2010-03-09 09:12:37 浏览 4,004 次

很多人都熟悉Twitter访问故障时候那条白色的鲸鱼。今年新推出的Twitter Engineering Blog讲述了Twitter白鲸技术故障的原因及解决思路。这是到目前为止Twitter公开的最底层的一篇技术资料。
http://engineering.twitter.com/2010/02/anatomy-of-whale.html

当Web Server发生503错误后,Twitter配置了一个前端鲸鱼的显示页面。Twitter对鲸鱼页面有监控体系,当每秒超过100个鲸鱼就会引起报警。

为什么在单位时间内会有大量的”fail whale”呢?Twitter成立了一个小组来专门分析此原因。

1. 分析背景资料

“分析性能问题不是一门科学,而是一门艺术”。

鲸鱼页面实际上是对HTTP 503错误的前端展示,503错误通常是调用后台请求超时产生,为了避免用户长时间等待,Twitter的前端(Tim: 也可能是HTTP反向代理)给请求加了超时,避免用户无限制的等待。超时通常是由于单位时间内访问的用户数过大,也有可能是后台某个服务突然变慢造成。
由于Twitter网站每个时刻都有海量的数据流过,因此要简单的定位并解决此问题并不容易。

2. Web page请求分解

Twitter的页面请求后端分成2个阶段,在Twitter内部称为IO phase及CPU phase。IO phase指通过网络服务获取用户的关注关系及相关的Tweets。第2阶段为CPU phase,指将数据聚合、排序及按用户请求的条件输出。IO及CPU各自在1天内消耗的时间如下。

从图上看到,latency增大时IO是主要瓶颈。IO对应于Network service,因此可以判断是某个网络服务性能降级造成。

3. 深度分析

理想情况是网络服务在应答相同参数的请求消耗时间应该基本相同。但实际情况并非如此,我们大胆假设某一网络服务性能下降厉害,于是我们就从统计分析中去寻找这个服务,我们看到Memcached的统计图表如下

4. Memcached 竟然是鲸鱼故障的直接原因

可提高的空间及解决思路

  1. 从上图看,Memcached在 latency高峰的性能比低谷相差一倍,因此最简单的判断是增加硬件即可提高50%的性能。
  2. 另外一种思路就是优化Memcached程序,判断程序热点和瓶颈并进行优化。

分析

  1. 通过 Google perf-tools project 工具来分析, http://code.google.com/p/google-perftools/ http://github.com/tmm1/perftools.rb
  2. 通过自己些的一段分析代码来监控 http://github.com/eaceaser/ruby-call-graph
  3. 通过上面工具的call graph来分析热点和瓶颈

最后分析数据Memcached请求分布比例如下

get         0.003s
get_multi   0.008s
add         0.003s
delete      0.003s
set         0.003s
incr        0.003s
prepend     0.002s

get         71.44%
get_multi    8.98%
set          8.69%
delete       5.26%
incr         3.71%
add          1.62%
prepend      0.30%

结论:从上面数据来看,调用热点和瓶颈主要集中在Get操作

因此回头取看Twitter页面执行流程代码,找出优化方法见注释。

get(["User:auth:missionhipster",              # 将昵称转换成uid
get(["User:15460619",                         # 获取user object(用于检查密码)
get(["limit:count:login_attempts:...",        # 防止密码字典攻击
set(["limit:count:login_attempts:...",        # 大部分情况不需要, bug
set(["limit:timestamp:login_attempts:...",    # 大部分情况不需要, bug
get(["limit:timestamp:login_attempts:...",
get(["limit:count:login_attempts:...",        # 重复调用,可记住
get(["limit:count:login_attempts:...",        # 重复调用
get(["user:basicauth:...",                    # 防止解密的优化
get(["limit:count:api:...",                   # 请求数限制
set(["limit:count:api:...",                   # 设置请求数,大部分情况不需要,为什么?
set(["limit:timestamp:api:...",               # 大部分情况不需要, bug
get(["limit:timestamp:api:...",
get(["limit:count:api:...",                   # 重复调用
get(["home_timeline:15460619",                # home_timeline业务调用
get(["favorites_timeline:15460619",           # favorites_timeline业务调用
get_multi([["Status:fragment:json:74736693",  # multi_get所有tweets内容

上面这段代码将17个请求优化成10个,部分重复调用通过本地cache避免,另外一些没必要的调用直接删除。通过一个简单的优化性能就提高了42%。

结论

  1. 在前文2010年的技术架构建议中提过Cache已经是Web 2.0系统核心元素。从Twitter的故障案例来看Memcached竟然成为了瓶颈并导致了Twitter服务的不稳定。由于在social应用中cache核心化的设计,“RAM is the new disk”,在cache广泛使用后也变得调用成本增加,需要考虑进行系统的规划减少不必要的调用。避免开发人员在代码中随意使用cache
  2. 如何定位瓶颈,可以借鉴Google perf-tools项目及上面其他分析工具的思路。
  3. Twitter页面执行流程值得参考
  4. 整个故障流程分析图如下

建议继续学习

  1. Twitter/微博客的学习摘要 (阅读 12,084)
  2. 别得瑟了,你很可悲! (阅读 7,803)
  3. Twitter架构图(cache篇) (阅读 5,982)
  4. PHP for Twitter OAuth 教学演示 (阅读 4,645)
  5. Twitter新员工的入职过程是怎样的? (阅读 4,483)
  6. 基于黄金分割率的Twitter新版页面布局探究 (阅读 3,725)
  7. 继续说说新版Twitter设计方面的事儿 (阅读 3,464)
  8. Twitter系统运维经验 (阅读 3,304)
  9. SNS背后的科学 (2) ―― 割裂的Web和割裂的Twitter (阅读 3,303)
  10. 新版twitter背后的技术 (阅读 3,203)