經典分佈式論文閱讀:Memcache

本文是Memcached論文的閱讀筆記,本文主要描述瞭如何使用memcached構建一個分佈式鍵值存儲系統。前端

一個社交網絡的基礎設施應該知足如下特性:數據庫

  1. 容許幾乎實時的通信;
  2. 從多個源頭快速聚合內容;
  3. 可以訪問和更新熱門的共享內容;
  4. 每秒可以處理百萬用戶請求。

本文以memcached爲基礎構建分佈式鍵值存儲系統,在特定的規模之下,某些特性須要更多的努力去知足。後端

總覽

如下兩個特性影響了系統的設計:緩存

  1. 用戶消費的內容比生產的內容多得多;
  2. 一個讀取操做須要從多個源頭獲取數據。=-

下文使用memcached指代源代碼或者運行中二進制文件,使用memcached指代分佈式系統。性能優化

查詢緩存memcache做爲demand-filled look-aside緩存來使用,當某個Web請求數據的時候,首先嚐試從緩存中獲取,若是緩存中不存在,那麼從後端獲取數據並寫回緩存,若是更新數據的話,須要將舊的數據從緩存中刪除。服務器

通用緩存memcache也能夠做爲通用的鍵值存儲來使用,例如保存機器學習計算結果等等。網絡

本文描述了不一樣尺度下的重點,可是始終強調兩個設計目標:數據結構

  1. 任何改進必須解決用戶或者運維問題;
  2. 將讀取到短暫的過期數據的可能性做爲能夠調整的參數。

集羣尺度:延遲和負載

memcache運行在集羣尺度上的時候,主要考慮的問題是減小解析緩存數據延遲和緩存缺失帶來的負載。多線程

下降延遲

memcache使用一致哈希將存儲對象分散到各個服務器上,所以所有Web服務器短期內會鏈接全部的服務器。下降延遲的工做主要在客戶端完成序列化、壓縮、請求路由、錯誤處理和批量請求等工做併發

並行請求和批量:可使用有向無環圖分析數據之間的依賴關係,使得一次請求獲取儘量多的鍵值。

客戶端-服務器通信:服務器之間不進行互相通訊,由客戶端處理系統複雜性。客戶端的邏輯由兩部分組成:

  • 一個可以嵌入應用程序的庫
  • 一個獨立的代理mcrouter

get請求使用UDP協議來下降延遲和負載,若是數據包丟失或者亂序將被視爲錯誤。Web服務器將客戶端錯誤視爲緩存缺失,可是從數據源獲取數據不作寫回。setdelete操做經過TCP協議進行。每一個線程建立一個鏈接很是浪費資源,運行在同一個機器上mcrouter將這些鏈接進行合併,提升網絡利用率。

請求擁塞memcache使用流控制機制來限制請求擁塞,客戶端使用滑動窗口來控制請求數量,窗口隨着成功請求數據而擴大,隨着未答覆請求而減少。

太小的窗口會致使沒必要要的等待,而過大的窗口會致使請求阻塞,須要找到平衡點。

下降負載

租期:系統使用了租期機制來解決過期數據驚羣效應。併發更新亂序以後會產生過期的數據。頻繁的寫入操做會頻繁地使得緩存失效,大量的讀取操做會同時轉向請求數據源。

當客戶端請求的緩存缺失的時候,服務器分配一個和鍵綁定的租期,在寫回數據的時候須要驗證租期合法性。若是驗證以前服務器收到過刪除請求,那麼租期就失效了。

驚羣效應能夠限制租期產生速率解決,例如10秒鐘一個,若是其餘客戶端在這個10秒以前請求對應的鍵,那麼讓它等待一小會兒時間,當客戶端再次嘗試的時候,數據通常已經在緩存之中。

某些場景下過期數據是能夠接受的,當數據被刪除後被轉移到一個保存最近刪除數據的數據結構中,存活一小段時間,一個獲取請求返回租期或者過期的數據。

Memcache池:不一樣的應用程序使用同一個memcache會相互干涉產生負做用,所以能夠考慮將memcached服務器分散到不一樣的池中,將不一樣讀寫特性的數據存入不一樣的池中。

在池中多副本:若是知足如下特性,那麼能夠在池中創建多副本:

  1. 應用同時請求不少鍵
  2. 整個數據集可以放在一個或者兩個memcached服務器中
  3. 請求速率遠超一個服務器可以處理能力

若是使用了多副本,那麼在使緩存失效時要對全部副本進行。

故障處理

咱們必須解決兩種規模下的故障:

  1. 由於網絡或者服務器錯誤致使少許主機不可達;
  2. 影響集羣中大部分服務器的大規模宕機。

對於小規模的宕機,系統設置了少許稱爲Gutter的機器來暫時管理不可用機器的鍵範圍,Gutter中的數據有效期很短,這樣避免了須要使緩存失效的操做。

區域尺度:副本

隨着負載規模增大,簡單地擴充機器是不夠的。做者將Web服務器和memcached服務器分爲多個前端集羣,和一個存儲集羣組成一個區域

區域失效

存儲集羣保存着最新數據,用戶請求將數據副本寫入到前端服務器。存儲集羣負責發送緩存失效命令,來保持數據的一致性。對數據產生修改的SQL會附上須要失效的mamcache鍵,應用更改以後由mcsqueal將緩存失效消息發送給各個前端集羣中的服務器。

下降數據包率:若是直接將失效緩存消息會浪費網絡資源,所以須要將緩存失效消息批量發送給每一個前端集羣中的mcrouter,再由mcrouter轉發給集羣內的服務器。

經過Web服務器失效:之因此不讓Web服務器直接發送緩存失效消息是由於:

  • 經過Web服務器進行批量處理比較低效
  • 在消息路由錯誤時候方便補救

區域池

集羣獨立地緩存數據,一個數據可能在多個集羣上有副本,能夠經過讓兩個集羣共享memcached服務器,這種形式稱爲區域池。能夠根據訪問速率、數據集大小和訪問用戶數量來決定是否將數據存入區域池。

集羣冷啓動

若是上線一個新的集羣,那麼剛開始負載都會指向數據庫。做者經過冷啓動預熱機制解決,容許Web服務器從其餘集羣獲取數據並寫回。

固然這樣會帶來不一致的問題,例如當一個客戶端更新了數據,同時另一個客戶端恰好轉向其餘集羣獲取數據,恰好緩存失效消息尚未到達。做者採用刪除拖延解決這個問題,在收到刪除消息兩秒以內禁止寫回。當客戶端寫回被拒絕後,說明數據已經被更新,須要從數據庫獲取。

跨區域:一致性

在多個地理位置部署數據中心有如下好處:

  1. 將Web服務器放在距離用戶近的位置能夠減小延遲
  2. 地理分散能夠緩解天然災害和斷電事故
  3. 新的地點可能會提供更廉價的電力以及其餘經濟效益

跨區域方式設計成一個區域管理主數據庫,其餘區域保存只讀副本。這樣帶來的一個問題就是:副本數據和主數據庫之間存在一些延遲。系統在強調性能和可用的同時,提供盡最大力的最終一致性。

寫入主區:使用mcsqueal傳輸失效消息能夠避免失效信息先於數據更新到達。

寫入非主區:若是一個非主區域的用戶更新了數據,那麼若是它接着從本地區域讀取數據可能看不到更改。這種狀況下要求必須在本地數據庫遇上以後才能重來填充緩存,做者使用了遠程標記來解決這個問題。

當Web服務器更新鍵值k時:

  1. 在區域創建一個遠程標記r_k
  2. 在主區域進行寫操做,並指示使k和r_k失效
  3. 刪除本地集羣上的k

這樣當k缺失的時候,若是客戶端看到r_k,那麼就去從主區域獲取數據。

運維考慮:跨區域通訊代價高,所以刪除消息和副本同步共用一個信道。

單機優化

性能優化memcached主要的性能優化爲:

  1. 容許哈希表自動展開,避免查詢時間退化到O(n)
  2. 讓多線程服務器使用全局鎖來保護多種數據結構
  3. 分配給線程獨立的UDP端口來避免數據傳輸競爭

自適應的slab分配器

memcached使用slab分配器管理內存,將內存空間塊組織成slab類,爲數據分配內存的時候會尋找符合其大小最小的塊,若是內存塊不足則繼續申請。當機器內存不足以分配新的內存塊是,淘汰類中的LRU內存塊。

做者優化了slab分配器來調整slab中內存塊數量來適應負載。若是某個類正在淘汰內存塊而且下一個要被淘汰的數據比每一類平均要淘汰的數據新20%,那麼說明這個類須要更多的內存塊。從當前保存全局LRU的slab中回收內存分配給這個slab。

短週期數據緩存:短期活動產生的短命鍵會浪費內存,做者使用混合策略來解決這個問題:對大多數鍵進行惰性回收,對短命鍵進行主動回收。把短命鍵數據放在一個按照過時時間排序的鏈表裏面,每秒鐘回收頭部的短命鍵。

軟件更新:爲了在軟件更新過程儘量減小中斷時間,做者修改了memcache,將緩存和數據結構保存在System V共享內存區域中,避免在更新時丟失數據。

參考文獻

  1. Nishtala, Rajesh, et al. "Scaling memcache at facebook." Presented as part of the 10th {USENIX} Symposium on Networked Systems Design and Implementation ({NSDI} 13). 2013.
相關文章
相關標籤/搜索