Facebook对memcached的提升

如果你翻阅过一些关于大型网站扩展(Scaling)的资料,那么你可能听说过一个叫memcached的东西。memcached是一个高性能、分布式的内存对象缓存系统。我们Facebook可能是世界上最大的memcached用户了。我们利用memcached来减轻数据库的负担。memcached确实很快,但是我们还要让他更快、更高效。我们使用了超过800台服务器,提供超过28TB的内存来服务于用户。在过去的一年里,随着Facebook的用户量直线上升,我们遇到了一系列的扩展问题。日益增长的需求使得我们必须对操作系统和memcached进行一些修改,以获得足够的性能来为我们的用户提供最好的体验。

因为我们有好几千台机器,每个都运行了几百个Apache进程甚至更多,最终导致到memcached进程的TCP链接有几十万个。这些链接本身并不是什么大问题,但是memcached为每个TCP链接分配内存的方法却很成问题。memcached为每个链接使用单独的缓存进行数据的读写。当达到几十万链接的时候,这些累计起来达好几个G——这些内存其实可以更好地用于存储用户数据。为了收复这些内存,我们实现了一个针对TCP和UDP套接字的每线程共享的链接缓存池。这个改变使每个服务器可以收回几个G的内存。

虽然TCP上我们改进了内存的使用效率,但我们还是转向了UDP,目的是让get(获取)操作能降低网络流量、让multi-get(同时并行地获取几百个键值)能实现应用程序级别的流量控制。我们发现Linux上到了一定负载之后,UDP的性能下降地很厉害。这是由于,当从多个线程通过单个套接字传递数据时,在UDP套接字锁上产生的大量锁竞争导致的。要通过分离锁来修复内核恐怕不太容易。所以,我们使用了分离的UDP套接字来传递回复(每个线程用一个答复套接字)。这样改动之后,我们就可以部署UDP同时后端性能不打折。

另一个Linux中的问题是到了一定负载后,某个核心可能因进行网络软终端处理会饱和而限制了网络IO。在Linux中,网络中断只会总是传递给某个核心,因此所有的接受软终端的网络处理都发生在该内核上。另外,我们还发现某些网卡有过高的中断频率。我们通过引入网络接口的“投机”轮询解决了这两个问题。在该模型中,我们组合了中断驱动和轮询驱动的网络IO。一旦进入网络驱动(通常是传输一个数据包时)以及在进程调度器的空闲循环的时候,对网络接口进行轮询。另外,我们也用到了中断(来控制延迟),不过网络中断用到的数量大大减少(一般通过大幅度提升中断联结阈值interrupt coalescing thresholds)。由于我们在每个核心上进行网络传输,同时由于在调度器的空闲循环中对网络IO进行轮询,我们将网络处理均匀地分散到每个核心上。

最后,当开始部署8核机器的时候,我们在测试中发现了新的瓶颈。首先,memcached的stat工具集依赖于一个全局锁。这在4核上已经很令人讨厌了,在8核上,这个锁可以占用20-30%的CPU使用率。我们通过将stats工具集移入每个线程,并且需要的时候将结果聚合起来。其次,我们发现随着传递UDP数据包的线程数量的增加,性能却在降低。最后在保护每个网络设备的传送队列的锁上发现了严重的争用。数据包是由设备驱动进行入队传输和出队。该队列由Linux的“netdevice”层来管理,它位于IP和设备驱动之间。每次只能有一个数据包加入或移出队列,这造成了严重的争用。我们当中的一位工程师修改了出队算法,实现了传输的批量出队,去掉了队列锁,然后批量传送数据包。这个更正将请求锁的开销平摊到了多个数据包,显著地减少了锁争用,这样我们就能在8核系统上将memcached伸展至8线程。

做了这些修改之后,我们可以将memcached提升到每秒处理20万个UDP请求,平均延迟降低为173微秒。可以达到的总吞吐量为30万UDP请求/s,不过在这个请求速度上的延迟太高,因此在我们的系统中用处不大。对于普通版本的Linux和memcached上的50,000 UDP请求/s而言,这是个了不起的提升。

我们希望尽快将我们的修改集成到官方的memcached仓库中去,我们决定在这之前,先将我们对memcached的修改发布到github上。

8 Comments

  1. Leo
    Leo
    2008年12月16日 at 4:15 下午 #

    望文生意,under load != underload 吧, 如果真是(欠载)负载过低,何谈”某个核心可能因进行网络软终端处理会饱和而限制了网络IO。” 前后逻辑都不对。


  2. ShiningRay
    2008年12月16日 at 4:18 下午 #

    @Leo

    文章的意思是在负载不高的情况下

    单个核心占用率100%不代表满负载,即使所有核心都100%占用率,负载也不一定非常高

    您认为应该如何翻译比较好


  3. Leo
    Leo
    2008年12月16日 at 4:25 下午 #

    Another issue we saw in Linux is that under load, one core would get saturated, doing network soft interrupt handing, throttling network IO.

    我真怀疑你是不是学计算机的,这句应该译为:

    我们遇到的另外一个问题是,当Linux在负荷很大时,一个核心因为处理网络软中断而饱和,就会抑制住网络IO.

    你的意思是,Linux在负载不高时,会试图让一个核忙死,另外的核都睡觉?


  4. ShiningRay
    2008年12月16日 at 4:27 下午 #

    @Leo

    多谢牛人提醒,我研究研究哈


  5. abdiazlzi
    abdiazlzi
    2008年12月27日 at 12:44 上午 #

    this is gr8. nice work gents


  6. &Frost
    &Frost
    2009年01月24日 at 10:21 上午 #

    能不能把英文也贴一下 好有个对照啊


  7. ShiningRay
    2009年01月25日 at 11:44 上午 #

    我不喜欢贴中英文对照版本的,因为那样1.好像是学英语2.好像是让别人想帮着校对
    英文原文就在
    http://www.facebook.com/note.php?note_id=39391378919
    你可以直接看看


  8. Herbert
    Herbert
    2009年04月16日 at 2:43 下午 #

    @Leo
    翻译的好不好,指正就可以了,干嘛说“我真怀疑你是不是学计算机的”。


One Trackback

  1. [...] 你看,整个设计是不是相当之简单?但正式这么简单地一个设计,Memcached大行其道,被很多站点所采用。facebook在一篇文章中,还重点讨论了很多关于如何优化它的好文,见这里,中文翻译见这里,总结可以见这里。而且可以看到facebook用Memcached在800台机器上,做了整整28T的缓存,那可是28T的内存数据,真的很夸张!所以,设计和运营这种大型的网站真是一件非常有挑战和有意思的工作。 [...]

Post a Comment

Your email is never published nor shared. Required fields are marked *

*
*
loading