# 解剖Twitter 【3】Cache == Cash

- 作者：邓侃
- 发布时间：2010-03-08 15:18
- 原文：https://www.ifanr.com/18818

Cache == Cash，缓存等于现金收入。虽然这话有点夸张，但是正确使用缓存，对于大型网站的建设，是至关重要的大事。网站在回应用户请求时的反应速度，是影响用户体验的一大因素。而影响速度的原因有很多，其中一个重要的原因在于硬盘的读写(Disk IO)。

Table 1 比较了内存(RAM)，硬盘(Disk)，以及新型的闪存(Flash)，在读写方面的速度比较。硬盘的读写，速度比内存的慢了百万倍。所以，要提高网站的速度，一个重要措施是尽可能把数据缓存在内存里。当然，在硬盘里也必须保留一个拷贝，以此防范万一由于断电，内存里的数据丢失的情况发生。

![解剖Twitter 【3】Cache == Cash](http://docs.google.com/File?id=drfcsw8_432r48dqpf5_b)

Table 1. Storage media comparison of Disk, Flash and RAM \[13\]   
Courtesy http://farm3.static.flickr.com/2736/4060534279\_f575212c12\_o.png

Twitter 工程师认为，一个用户体验良好的网站，当一个用户请求到达以后，应该在平均500ms以内完成回应。而Twitter的理想，是达到200ms- 300ms的反应速度\[17\]。因此在网站架构上，Twitter大规模地，多层次多方式地使用缓存。Twitter在缓存使用方面的实践，以及从这些实践中总结出来的经验教训，是Twitter网站架构的一大看点。

![解剖Twitter 【3】Cache == Cash](http://docs.google.com/File?id=drfcsw8_435frxxqvfn_b)

Figure 2. Twitter architecture with Cache   
Courtesy http://farm3.static.flickr.com/2783/4065827637\_bb2ccc8e3f\_o.png

哪里需要缓存？越是Disk IO频繁的地方，越需要缓存。

前面说到，Twitter业务的核心有两个，用户和短信(Tweet)。围绕这两个核心，数据库中存放着若干表，其中最重要的有三个，如下所示。这三个表的设置，是旁观者的猜测，不一定与Twitter的设置完全一致。但是万变不离其宗，相信即便有所不同，也不会本质区别。

1\. 用户表：用户ID，姓名，登录名和密码，状态（在线与否）。   
2\. 短信表：短信ID，作者ID，正文（定长，140字），时间戳。   
3\. 用户关系表，记录追与被追的关系：用户ID，他追的用户IDs (Following)，追他的用户IDs (Be followed)。

有没有必要把这几个核心的数据库表统统存放到缓存中去？Twitter的做法是把这些表拆解，把其中读写最频繁的列放进缓存。

1\. Vector Cache and Row Cache

具体来说，Twitter工程师认为最重要的列是IDs。即新发表的短信的IDs，以及被频繁阅读的热门短信的IDs，相关作者的IDs，以及订阅这些作者的读者的IDs。把这些IDs存放进缓存 (Stores arrays of tweet pkeys \[14\])。在Twitter文献中，把存放这些IDs的缓存空间，称为Vector Cache \[14\]。

Twitter工程师认为，读取最频繁的内容是这些IDs，而短信的正文在其次。所以他们决定，在优先保证Vector Cache所需资源的前提下，其次重要的工作才是设立Row Cache，用于存放短信正文。

命中率(Hit Rate or Hit Ratio)是测量缓存效果的最重要指标。如果一个或者多个用户读取100条内容，其中99条内容存放在缓存中，那么缓存的命中率就是99%。命中率越高，说明缓存的贡献越大。

设立Vector Cache和Row Cache后，观测实际运行的结果，发现Vector Cache的命中率是99%，而Row Cache的命中率是95%，证实了Twitter工程师早先押注的，先IDs后正文的判断。

Vector Cache和Row Cache，使用的工具都是开源的MemCached \[15\]。

2\. Fragment Cache and Page Cache

前文说到，访问Twitter网站的，不仅仅是浏览器，而且还有手机，还有像QQ那样的电脑桌面工具，另外还有各式各样的网站插件，以便把其它网站联系到Twitter.com上来\[12\]。接待这两类用户的，是以Apache Web Server为门户的Web通道，以及被称为“API”的通道。其中API通道受理的流量占总流量的80%-90% \[16\]。

所以，继Vector Cache和Row Cache以后，Twitter工程师们把进一步建筑缓存的工作，重点放在如何提高API通道的反应速度上。

读者页面的主体，显示的是一条又一条短信。不妨把整个页面分割成若干局部，每个局部对应一条短信。所谓Fragment，就是指页面的局部。除短信外，其它内容例如Twitter logo等等，也是Fragment。如果一个作者拥有众多读者，那么缓存这个作者写的短信的布局页面(Fragment)，就可以提高网站整体的读取效率。这就是Fragment Cache的使命。

对于一些人气很旺的作者，读者们不仅会读他写的短信，而且会访问他的主页，所以，也有必要缓存这些人气作者的个人主页。这就是Page Cache的使命。

Fragment Cache和Page Cache，使用的工具也是MemCached。

观测实际运行的结果，Fragment Cache的命中率高达95%，而Page Cache的命中率只有40%。虽然Page Cache的命中率低，但是它的内容是整个个人主页，所以占用的空间却不小。为了防止Page Cache争夺Fragment Cache的空间，在物理部署时，Twitter工程师们把Page Cache分离到不同的机器上去。

3\. HTTP Accelerator

解决了API通道的缓存问题，接下去Twitter工程师们着手处理Web通道的缓存问题。经过分析，他们认为Web通道的压力，主要来自于搜索。尤其是面临突发事件时，读者们会搜索相关短信，而不理会这些短信的作者，是不是自己“追”的那些作者。

要降低搜索的压力，不妨把搜索关键词，及其对应的搜索结果，缓存起来。Twitter工程师们使用的缓存工具，是开源项目Varnish \[18\]。

比较有趣的事情是，通常把Varnish部署在Web Server之外，面向Internet的位置。这样，当用户访问网站时，实际上先访问Varnish，读取所需内容。只有在Varnish没有缓存相应内容时，用户请求才被转发到Web Server上去。而Twitter的部署，却是把Varnish放在Apache Web Server内侧\[19\]。原因是Twitter的工程师们觉得Varnish的操作比较复杂，为了降低Varnish崩溃造成整个网站瘫痪的可能性，他们便采取了这种古怪而且保守的部署方式。

Apache Web Server的主要任务，是解析HTTP，以及分发任务。不同的Mongrel Rails Server负责不同的任务，但是绝大多数Mongrel Rails Server，都要与Vector Cache和Row Cache联系，读取数据。Rails Server如何与MemCached联系呢？Twitter工程师们自行开发了一个Rails插件(Gem)，称为CacheMoney。

虽然Twitter没有公开Varnish的命中率是多少，但是\[17\]声称，使用了Varnish以后，导致整个Twitter.com网站的负载下降了50%，参见Figure 3.

![解剖Twitter 【3】Cache == Cash](http://docs.google.com/File?id=drfcsw8_433chqtvbqf_b)

Figure 3. Cache decreases Twitter.com load by 50% \[17\]   
Courtesy http://farm3.static.flickr.com/2537/4061273900\_2d91c94374\_o.png

Reference,

\[12\] Alphabetical List of Twitter Services and Applications.   
([http://en.wikipedia.org/wiki/List\_of\_Twitter\_services\_and\_applications](http://en.wikipedia.org/wiki/List_of_Twitter_services_and_applications))   
\[13\] How flash changes the DBMS world.   
(<http://hansolav.net/blog/content/binary/HowFlashMemory.pdf>)   
\[14\] Improving running component of Twitter.   
(<http://qconlondon.com/london-2009/file?path=/qcon-london-2009/slides/>   
EvanWeaver\_ImprovingRunningComponentsAtTwitter.pdf)   
\[15\] A high-performance, general-purposed, distributed memory object caching system.   
(<http://www.danga.com/memcached/>)   
\[16\] Updating Twitter without service disruptions.   
(<http://gojko.net/2009/03/16/qcon-london-2009-upgrading-twitter-without-service-disruptions/>)   
\[17\] Fixing Twitter. (<http://assets.en.oreilly.com/1/event/29/>   
Fixing\_Twitter\_Improving\_the\_Performance\_and\_Scalability\_of\_the\_World\_s\_   
Most\_Popular\_Micro-blogging\_Site\_Presentation%20Presentation.pdf)   
\[18\] Varnish, a high-performance HTTP accelerator.   
(<http://varnish.projects.linpro.no/>)   
\[19\] How to use Varnish in Twitter.com?   
(<http://projects.linpro.no/pipermail/varnish-dev/2009-February/000968.html>)   
\[20\] CacheMoney Gem, an open-source write-through caching library.   
(<http://github.com/nkallen/cache-money>)
