原文見於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文件裏面了。