原文见于http://shiningray.cn/scaling-memcached-at-facebook.html,不过此文对翻译进行了一些自认为的修改和内容的概括总结。这里有英文原文:http://guojuanjun.blog.51cto.com/277646/735854 html
http://www.facebook.com/notes/facebook-engineering/scaling-memcached-at-facebook/39391378919 git
Memcached确实很快了,可是Facebook仍是对Memcached进行了4处大的修改来进一步提高Memcached的性能。浏览下面的4个修改,不难发现其中2个都和“严重的锁竞争”有关。修改1主要是节省了大量内存,因此减小“锁竞争”对性能提高的贡献估计能达到70%左右,因而可知“锁竞争”的可怕!!!。修改后的代码在这里:https://github.com/fbmarc/facebook-memcached-old(根据文章中的连接找到的) github
固然Facebook对Memcached的优化也不能说明Memcached不好,正是由于它足够优秀,Facebook这种牛人云集的公司才会用它。并且Memcached自身的文档也提到了在多线程状况下性能会由于锁竞争降低,见最下面一段。 算法
原状:memcached为“每一个TCP连接”使用单独的缓存(a per-connection buffer)进行数据的读写。 数据库
问题:当达到几十万连接的时候,这些累计起来达好几个G——这些内存其实能够更好地用于存储用户数据。方案:实现了一个针对TCP和UDP套接字的“每线程共享”的连接缓存池(a per-thread shared connection buffer pool for TCP and UDP sockets)。 后端
效果:这个改变使每一个服务器能够收回几个G的内存。新问题:咱们发现Linux上到了必定负载以后,UDP的性能降低地很厉害。 缓存
新问题缘由:当从多个线程经过单个套接字传递数据时,在UDP套接字锁上产生的大量锁竞争(considerable lock contention)致使的。新问题方案:要经过分离锁来修复代码核心不太容易。因此,咱们使用了分离的UDP套接字来“传递回复”(每一个线程用一个回复套接字)。 服务器
新问题解决效果:这样改动以后,咱们就能够部署UDP同时后端性能不打折。问题:(1)Linux中的问题是到了必定负载后,某个核心可能因进行网络软终端处理会饱和而限制了网络IO。(2)特定的网卡有特别高的中断频率。 网络
问题(1)的缘由:在Linux中,网络中断只会老是传递给某个核心,所以全部接收到的软中断网络处理都发生在该核心上。 多线程
解决:咱们经过引入网络接口的“投机”轮询(“opportunistic” polling of the network interfaces)解决了这两个问题。在该模型中,咱们综合了中断驱动和轮询驱动的网络IO。一旦进入网络驱动(一般是传输一个数据包时)以及在进程调度器的空闲循环的时候,对网络接口进行轮询。另外,咱们仍是用到了中断(来控制延迟),不过用到的网络中断数量相比大大减小了(通常经过大幅度提高中断联结阈值interrupt coalescing thresholds)。
效果:因为咱们在每一个核心(core)上进行网络传输,同时因为在调度器的空闲循环中对网络IO进行轮询,咱们将网络处理均匀地分散到每一个核心(core)上。问题:memcached的stat收集依赖于一个全局锁。这在4核上已经很使人讨厌了,在8核上,这个锁能够占用20-30%的CPU使用率。
方案:咱们经过将stat收集移入每一个线程,而且须要的时候将结果聚合起来。问题:随着传输UDP数据包的线程数量的增长,性能却在下降。
缘由:保护每一个网络设备的传送队列的锁上发现了严重的争用(significant contention)。传输时将数据包入队,而后设备驱动进行出队操做。该队列由Linux的“netdevice”层来管理,它位于IP和设备驱动之间。每次只能有一个数据包加入或移出队列,这形成了严重的争用(causing significant contention)。
方案:一位工程师修改了出队算法以达到传输时候的批量出队,去掉了队列锁(drop the queue lock)。这样就能够批量传送数据包了。
效果:将锁请求(the lock acquisition)的开销平摊到了许多个数据包上,显著地减小了锁争用(reduces lock contention significantly),这样咱们就能在8核系统上将memcached伸展至8线程。20万/s相对于5万,这个性能提高太吓人了!!!
不过Memcached源码doc目录下的thread.txt也有这样的一句话:
Due to memcached's nonblocking architecture, there is no real advantage to using more threads than the number of CPUs on the machine; doing so will increase lock contention and is likely to degrade performance.
而后还提到了当前的锁的粒度比较粗,对于在大规模并行的机器上运行仍是有不少优化空间的。也提到了全部客户端都共享一个UDP套接字。
因此使用开源软件以前仍是最好先阅读下它的相关文档,ChangeNodes,TODO等。好比这里就有一个教训:http://blog.codingnow.com/2009/06/tcc_bug.html 花了不少时间确认了Tcc的一个bug,可是后来才发现,这个bug早就在TODO文件里面了。