論文筆記:Scaling Memcache at Facebook
論文介紹了Facebook如何使用memcache,以及相關魔改和維護memcache集羣。web
歡迎訪問個人博客數據庫
背景
facebook使用一致性哈希來構建memcahce集羣。後端
We provision hundreds of memcached servers in a cluster to reduce load on databases and other services.
Items are distributed across the memcached servers through consistent hashing [22].
Thus web servers have to routinely communicate with many memcached servers to satisfy a user request
使用
cache aside模式
facebook根據他們的場景,也就是讀多寫少使用了cache aside模式。原文叫demand-filled look-aside cache。具體使用方式以下圖。
facebook 使用delete而不是update緩存的緣由是由於delete是冪等的,而update不是(we choose to delete cached data instead of updating it because deletes are idempotent).若是直接更新可能出現先更新的後放入緩存。緩存
在facebook也是用memcache做爲大數據平臺計算的中間結果存儲平臺,用來存放一些中間結果服務器
魔改
魔改背景
一個web請求會請求平均521個獨立的緩存項.(A single user web request can often result in hundreds of individual memcache get requests. For example, loading one of our popular pages results in an average of 521 distinct items fetched from memcache)網絡
魔改目的
魔改的目的是爲了下降延遲,下降負載。數據結構
魔改方法
延遲與負載:1.網絡延遲 2.因爲cache miss帶來的延遲和後端的負載。解決方案以下:ide
- 代碼批量化訪問緩存,減小來回的網絡開銷
- 對於網絡延遲的下降,facebook對於GET使用UDP傳輸,SET和DELETE使用TCP傳輸。由於UDP是無鏈接的,能夠下降TCP維護連接的開銷。使用UDP客戶端本身記錄請求序號,丟包和亂序被視爲客戶端錯誤,在實際生產環境中,有0.25%的get請求被扔掉。其中的80%是由於回包延遲,其餘的是由於亂序。對於上面的錯誤,客戶端直接認爲是cache miss。直接取後端,可是不會放入緩存是爲了不額外的網絡開銷
效果以下圖:
- 使用相似TCP擁塞控制的方法來防止緩存集羣負載太高。客戶端維護一個滑動窗口,當服務端正常響應,就加大窗口,當服務端沒響應或者超時就減少窗口。
後端負載下降
1.引入「租約Leases」,租約用來解決兩個方面的問題 1. 過時的設置 2.驚羣效應(stale sets and thundering herds)。memcached
- 過時的設置主要來源於放入緩存的順序錯亂(後來先到)。
- 驚羣效應發生在某個key被頻繁的讀寫。因爲寫是invalid cache,因此大量讀請求就會沒法命中緩存,致使進入了後端的數據庫。
- 租約就是一個對應於請求的key的64bit的token。(The lease is a 64-bit token bound to the specific key the client originally requested)。當set cache的時候,客戶端須要把這個key帶上一塊兒給到緩存服務器,當服務端發現token不匹配的時候,就說明這是一個過時的寫請求。
- 租約同時能夠下降驚羣效應。緩存服務器控制發token的頻率,默認是10秒一次,緩存服務器發過一次token後,後續再來的請求就直接等一會(等前面那個拿到token的返回以後,緩存就有數據了)
Without leases, all of the cache misses resulted in a peak database query rate of 17K/s. With leases, the peak database query rate was 1.3K/s
2.使用過時值fetch
- 經過返回slightly out-of-date data,當一個key被刪除的時候,在真正flush以前,會被放入一個特殊的數據結構中。get請求能夠返回一個租約或者這個被標記爲過時的值。
3.處理失敗,這裏的失敗有兩種
- 有一小部分機器因爲網絡緣由沒法訪問(facebook依賴一個自動化的組件去發現這些機器,但須要時間 few minutes,在這一段時間內可能會帶來一些連鎖失敗)
解決辦法:有一個叫gutter的小池子,大概是cache集羣的1%大小,用來替代那些沒法訪問的機器。當client沒法收到緩存服務器的響應,他們就去訪問gutter池子裏面的機器。注意這根通常一致性哈希的玩法不同,緣由是有可能有些key很是的熱,若是把它hash到下一臺機器,就會增長那臺機器的負載,致使又爆炸。把它導到空閒的gutter機器上就能夠避免這個問題。一旦出現一臺緩存機器沒法訪問,gutter一般能在4分鐘內,緩存命中率能超過35%,有時能達到50%
- 集羣中的大部分機器都沒法訪問
解決辦法:切換流量到其餘可用region
維護memcache集羣
待續