Facebook 对 Memcache 伸缩性的增强
| 概要:Memcached 是一個知名的,簡單的,全內(nèi)存的緩存方案。這篇文章描述了facebook是如何使用memcached來構(gòu)建和擴展一個分布式的key-value存儲來為世界上最大的社交網(wǎng)站服務(wù)的。我們的系統(tǒng)每秒要處理幾十億的請求,同時存儲了幾萬億的數(shù)據(jù)項,可以給全世界超過10億的用戶提供豐富體驗。 1 介紹近些年SNS網(wǎng)絡(luò)大行其道,這對網(wǎng)站基礎(chǔ)建設(shè)提出了巨大的挑戰(zhàn)。每天有億萬的用戶在使用這些網(wǎng)絡(luò)服務(wù),巨大的計算、網(wǎng)絡(luò)和I/O資源的需求使傳統(tǒng)的web架構(gòu)不堪重 負。SNS網(wǎng)站的基礎(chǔ)架構(gòu)需要滿足:1、近乎實時的交流;2、即時聚合不同來源的內(nèi)容;3、訪問和更新非常熱門的共享內(nèi)容;4、每秒處理幾百萬的用戶請求。 |
?
| 我們將描述我們是如何改進memcached[14]的開源版本,并且用它作為組件來構(gòu)建用于世界上最大的社會化網(wǎng)絡(luò)的分布式key-value存儲的。我們會討論從單集群服務(wù)器擴展成地理上分布式的多集群的歷程。據(jù)我們所知,這個系統(tǒng)是世界上已安裝的規(guī)模最大的memcached系統(tǒng),每秒可以處理幾十億的請求,存儲數(shù)以萬億的數(shù)據(jù)項。 本文是關(guān)于認識分布式key-value存儲的靈活性和實用性的系列文章[1, 2, 5, 6, 12, 14, 34, 36]的最后一篇。本文關(guān)注于memcached,這是一個全內(nèi)存哈希表的開源實現(xiàn),它以較低的開銷提供了對共享存儲的低遲延訪問。有了這些特性我們可以構(gòu)建數(shù)據(jù)密集的功能,否則是不可能的。例如,如果一個頁面請求會產(chǎn)生數(shù)以百計的數(shù)據(jù)庫請求,那么這樣的功能只能停止在原型階段,因為實現(xiàn)起來會太慢,代價也太高。然而,在我們的應(yīng)用里,web頁面通常都會從memcached服務(wù)器獲取數(shù)以千計的key-value對。 |
| 我們的目標之一,是展現(xiàn)部署在不同尺度(系統(tǒng))上的重要主題。雖然在所有尺度上是很重要的品質(zhì),如性能,效率,容錯性和一致性,我們的經(jīng)驗表明,在特定大小的一些素質(zhì)要求比別人更多的努力來實現(xiàn)。舉例來說,保持數(shù)據(jù)的一致性,如果復(fù)制的內(nèi)容是小量的,可以更容易在小尺度的網(wǎng)絡(luò)上實現(xiàn),相比較大的網(wǎng)絡(luò)往往只是復(fù)制必要的內(nèi)容。此外,找到一個最佳的通信調(diào)度的重要性增加的數(shù)量增加服務(wù)器和網(wǎng)絡(luò)工作成為瓶頸。 ??????????? 本文包括四個主要貢獻:(1)我們描述了Facebook的基于memcach架構(gòu)的演化。 (2)我們確定memcached的提高性能和增加內(nèi)存效率的改進。 (3)我們簡明扼要地講述提高我們的經(jīng)營能力我們的系統(tǒng)規(guī)模的機制。 (4)我們對生產(chǎn)工作負載賦予了特色(譯者加:對工作負載進行了分類?)。 ? |
2綜述以下特點大大影響了我們的設(shè)計。第一,用戶閱讀的內(nèi)容比他們創(chuàng)建的要多一個數(shù)量級,這種行為(讀寫的特點)所產(chǎn)生工作負載,顯然讓緩存可以發(fā)揮很大的優(yōu)勢。第二,我們是從多個來源讀取數(shù)據(jù)的,比如MySQL數(shù)據(jù)庫、HDFS設(shè)備和后臺服務(wù),這種多樣性要求一個靈活的緩存策略,能夠從各個獨立的源中儲存數(shù)據(jù)。 MemCached提供了一組簡單的操作(set、get和delete),使它在一個大規(guī)模的分布式系統(tǒng)中成為注目的基礎(chǔ)組件。開源版本提供了單機內(nèi)存哈希表,在本文中,我們從這個開源版本開始,討論我們是怎么使用這個基礎(chǔ)組件,使它變得更有效,并用它來建一個可以處理每秒數(shù)十億請求的分布式的鍵-值儲存系統(tǒng)。接下來,我們用“memcached”來指代它的源碼或者它運行的二進制實例,用“memcache”來指代由每個實例構(gòu)成的分布式系統(tǒng)。 ? 圖1:Memcache作為填補需求的旁路緩存系統(tǒng)。左半圖說明了WEB服務(wù)器讀取緩存時命中失敗的讀取路徑,右半圖說明其寫路徑。 |
| 查詢緩存:我們依賴于memcache來減輕讀取數(shù)據(jù)庫的負擔(dān)。特別的,我們使用memcache作為填補需求的旁路緩存系統(tǒng),如圖1。當一個Web服務(wù)器需要數(shù)據(jù)時,首先通過一個字符串的鍵在memcache中請求,如果沒有找到,它會從數(shù)據(jù)庫或者從后臺服務(wù)中檢索,再使用該鍵把結(jié)果存回memcache中。對于寫的請求,Web服務(wù)器發(fā)送SQL語句到數(shù)據(jù)庫,接著發(fā)送刪除請求到memcache,使舊的緩存數(shù)據(jù)失效。因為刪除是冪等運算,所以我們使用刪除緩存的方式,而不是更新緩存。 在應(yīng)對MySQL數(shù)據(jù)庫繁重的查詢通信的眾多方法中,我們選擇了memcache,在有限的資源與時間限制下,這是最好的選擇。此外,緩存層與持久層分離,讓我們可以在工作負載發(fā)生變化時快速地調(diào)整。 |
| 通用緩存:我們同樣讓memcache成為一個更加通用的鍵-值儲存系統(tǒng)。比如說,工程師們使用memcache保存復(fù)雜的機器學(xué)習(xí)算法的中間結(jié)果,這些結(jié)果能被很多其它應(yīng)用程序所使用。它只需要我們付出很少的努力,就可以讓新增的服務(wù)利用現(xiàn)有的正在使用的基礎(chǔ)設(shè)施,而無需調(diào)整、優(yōu)化、調(diào)配和維護大型的服務(wù)器群。 正如memcached沒有提供服務(wù)器到服務(wù)器的協(xié)同,它僅僅是運行在單機上的一個內(nèi)存哈希表。接下來我們描述我們是如何基于memcached構(gòu)建一個分布式鍵值儲存系統(tǒng),以勝任在Facebook的工作負載下的操作。 圖2:整體架構(gòu) |
| 論文的結(jié)構(gòu)主要描述了在三種不同的規(guī)模下出現(xiàn)的問題。當我們擁有第一個服務(wù)器集群時,頻繁的讀負載和廣泛的輸出是我們最大的擔(dān)心。當有必要擴展到多個前端集群時,我們解決了集群間的數(shù)據(jù)備份問題。最后,我們描述了一種機制,這種機制讓我們可以在全世界伸展集群的同時提供平滑的用戶體驗。不論在什么尺度上,容錯性和操作復(fù)雜性總是很重要的。我們展示了重要的數(shù)據(jù)參考,這些數(shù)據(jù)指引我們做出了最終的設(shè)計決定,讀者如需獲得更多細節(jié)性的分析,請參看Atikoglu et al.[8]的工作。提綱挈領(lǐng)的解釋參看圖2,這是最終的架構(gòu),我們將并置集群組織起來,形成一個群體(region),指定一個主群體(master),由主群體提供數(shù)據(jù)流讓非主群體保持數(shù)據(jù)同步。 ??????????? 在系統(tǒng)的發(fā)展中,我們將這兩個重大的設(shè)計目標放在首位: 1. 只有已經(jīng)對用戶或者我們的運維產(chǎn)生影響的問題,才值得改變。我們極少考慮范圍有限的優(yōu)化。 2. 對陳舊數(shù)據(jù)的瞬態(tài)讀取,其概率和響應(yīng)度類似,都將作為參數(shù)來調(diào)整。我們會暴露輕度陳舊的數(shù)據(jù)以便后臺存儲和高強度負載絕緣。 ? |
3 集群之中: 延遲和負載現(xiàn)在考慮集群中數(shù)以千計的服務(wù)器所帶來的挑戰(zhàn)。在這種規(guī)模之下,我們著眼于減少獲取緩存時的負載,以及緩存不中時數(shù)據(jù)庫的負載。 3.1 減少延遲不論緩存是否命中,memcache的響應(yīng)時間都是影響總響應(yīng)時間的重要因素。單個的網(wǎng)頁請求一般包含數(shù)百個memcache讀請求。如一個較火的頁面平均需要從memcache中獲取521個不同的資源。 為了減少數(shù)據(jù)庫等的負擔(dān),我們準備了緩存集群,每個集群都由數(shù)百臺memcache服務(wù)器組成。資源個體經(jīng)hash后存于不同的memcache服務(wù)器中。因此,web服務(wù)器必須請求多臺memcache服務(wù)器,才能滿足用戶的請求。由此導(dǎo)致在很短的時間里每個web服務(wù)器都要和所有的memcache服務(wù)器溝通。這種所有對所有的連接模式會導(dǎo)致潮涌堵塞(incast congestion)或者某臺服務(wù)器不幸成為瓶頸。實時備份可以緩解這種狀況,但一般又會引起巨大的內(nèi)存浪費。(譯者:為何?) |
| 我們減少延遲的方法主要集中在memcache客戶端,每一個web服務(wù)器都會運行memcache客戶端。這個客戶端提供一系列功能,包括:串行化、壓縮、請求路由、錯誤處理以及請求批處理。客戶端維護著一個對所以可獲得的服務(wù)器的映射,對這個映射表的更新需要通過一個輔助的配置系統(tǒng)。 并行請求和批處理:我們構(gòu)建web應(yīng)用代碼,目的是最小化對于頁面請求回應(yīng)所必要的網(wǎng)絡(luò)往返數(shù)。我們構(gòu)建了有向無環(huán)圖(DAG)用來表示數(shù)據(jù)間的依賴。web服務(wù)器使用DAG來最大化可以并發(fā)讀取的項目數(shù)。平均來說,這些批量請求對于每個請求包含24個主鍵。 客戶端-服務(wù)器通信:memcached服務(wù)器不會直接通信。如果適當,我們將系統(tǒng)的復(fù)雜度嵌入無狀態(tài)的客戶端,而不是memcached服務(wù)器。這極大地簡化了memcached,使我們專注于針對更有限的用例提供高性能。保持客戶端的無狀態(tài)使得我們可以快速迭代開發(fā),同時也簡化了部署流程。客戶端的邏輯可以提供為兩種組件:可以嵌入應(yīng)用的一個庫,或者做為一個名為mcrouter的獨立的代理程序。這個代理提供memcached服務(wù)器的借口,對不同服務(wù)器之間的請求/回復(fù)進行路由。 |
| 客戶端使用UDP和TCP協(xié)議與memcached服務(wù)器通訊。我們依賴UDP來使請求的延遲和開銷縮減。因為UDP是無連接的,web服務(wù)器中的每個線程都被允許直接與memcached服務(wù)器通信,通過mcrouter,不需要創(chuàng)建與維護連接因而減少了開銷。UDP實現(xiàn)了檢測出丟失的或失序接收(通過序列號)的包,并在客戶端將它們作為異常處理。它沒有提供任何試圖恢復(fù)的機制。在我們的基礎(chǔ)架構(gòu)中,我們發(fā)現(xiàn)這個決定很實際。在峰值負載條件下,memcache客戶端觀察到0.25%的請求會被丟棄。其中大約80%是由于延遲或丟失包,其余的是由于失序的交付。客戶端將異常作為緩存不命中處理,但是web服務(wù)器在查詢出數(shù)據(jù)以后,會跳過插入條目到memcached,以便避免對可能超載的網(wǎng)絡(luò)會服務(wù)器增添額外的負載。 圖 3: 經(jīng)過mcrouter以后 UDP, TCP得到的延遲 |
| 為了可靠性,客戶端通過同一個web服務(wù)器上運行的mcrouter實例,在TCP協(xié)議之上運行set與delete操作。對我們需要確認狀態(tài)變化(更新和刪除)的操作,TCP避免了UDP實現(xiàn)中增加重試機制的必要。 Web服務(wù)器依賴很高程度的并行性與超量提交來獲得高吞吐量。如果不采用由mcrouter合并的某種形式的連接,打開TCP連接需要的大量內(nèi)存將使得在每個web線程與memcached服務(wù)器之間打開連接變得尤其代價昂貴。通過減少高吞吐量TCP連接對網(wǎng)絡(luò),CPU和內(nèi)存資源的需求,合并這些連接的方式增強了服務(wù)器的效率。圖3顯示了生產(chǎn)環(huán)境中web服務(wù)器在平均的,中級的,以及百分之95的條件下,在UDP和通過經(jīng)由TCP的mcrouter機制下獲得關(guān)鍵字的延遲。在所有情形,與這些平均值的標準差小于1%。正如數(shù)據(jù)所示,依賴UDP能有20%的延遲縮減來對請求提供服務(wù)。 ================= ======================= 1 百分之95的頁面抓取的是1,740項目。 2 百分之95情形是每個請求有95個關(guān)鍵字。 |
| Incast擁塞:memcache客戶端實現(xiàn)流量控制機制限制incast擁塞。當一個客戶端請求大量的主鍵時,如果所有應(yīng)答同時達到,那么這些應(yīng)答可以淹沒一些組件,例如:機架和集群交換機。因此客戶端使用滑動窗口機制[11]來控制未處理請求的數(shù)量。當客戶端收到一個應(yīng)答的時候,那么下一個請求就可以發(fā)送了。與TCP的擁塞控制類似,滑動窗口的大小隨著成功的請求緩慢的增長,當一個請求沒有應(yīng)答的時候就縮小。這個窗口應(yīng)用于所有的memcache請求,而不關(guān)心目的地址;然而TCP窗口僅僅應(yīng)用于單獨的數(shù)據(jù)流。 ??????????? 圖4:web請求平均等待調(diào)度時間 |
| 圖4展示了窗口大小對web服務(wù)器中處于運行態(tài)的用戶請求等待調(diào)度總時間的影響。這些數(shù)據(jù)從一個前端集群的多臺機架采集而來。在每個web服務(wù)器,用戶請求呈現(xiàn)泊松到達過程。參照Little定律[26],L=λW,假設(shè)輸入請求速率是恒定的(在我們的試驗中就是這樣),在服務(wù)器排隊的請求數(shù)量(L)正比于處理請求的平均時間(W)。web請求的等待調(diào)度時間是web請求在系統(tǒng)中數(shù)量的一個直接指標。當窗口比較小的時候,應(yīng)用將不得不串行地分發(fā)更多組memcache請求,這將會增加web請求的持續(xù)時間。當窗口過大的時候,同時處理的memcache請求的數(shù)量將會引發(fā)incast擁塞。結(jié)果將會是memcache錯誤,應(yīng)用退化到從持久化存儲中取數(shù)據(jù),這樣將會導(dǎo)致對web請求的處理更緩慢。在這兩個極端之間有一個平衡,處于這個平衡的時候,不必要的延遲將會避免,同時incast擁塞可以被最小化。 |
| 3.2 減少負載 ??????????? 我們使用memcache來減少用更耗時的方式讀數(shù)據(jù)的頻率,比如數(shù)據(jù)庫查詢。當期望的數(shù)據(jù)沒有被緩存的時候,web服務(wù)器將會退化到使用更耗時方式。下述子章節(jié)將會描述三種技術(shù),用來減少負載。 3.2.1 租約(leases) 我們引入了一個稱為租約(leases)的新機制來解決兩個問題:過時設(shè)置(stale sets)和驚群(thundering herds)。當web服務(wù)器更新一個在緩存中不是最新版本的值的時候,一次過時設(shè)置就發(fā)生了。當對memcache的并發(fā)更新重新排序的時候,這種情況是會發(fā)生的。當某個特定的主鍵被大量頻繁的讀寫,那么一次驚群就發(fā)生了。因為寫操作反復(fù)地使最近設(shè)置的值失效,那么讀操作將會默認地使用更耗時的方式。我們的租約機制解決了這兩個問題。 [譯者注:此處的leases與Cary G. Gray的leases不一樣,不要混淆。] ? |
| 直觀地,當這個客戶端發(fā)生緩存不命中時,memcached實例給客戶端一個租約,將數(shù)據(jù)設(shè)置到緩存中。租約是一個64bit的令牌,與客戶端初始請求的主鍵綁定。當設(shè)值到緩存中時,客戶端提供這個租約令牌。通過這個租約令牌,memcached可以驗證和判斷是否這個數(shù)據(jù)應(yīng)該被存儲,由此仲裁并發(fā)寫操作。如果因為收到了對這個數(shù)據(jù)項的刪除請求,memcached使這個租約令牌失效,那么驗證操作將會失敗。租約阻止過時設(shè)置的方法類似于load-link/store-conditional操作[20]。 ??????????? 對租約的輕微改動也可以緩和驚群這個問題。每個memcached服務(wù)器調(diào)節(jié)返回令牌的速率。默認情況,我們配置服務(wù)器對于每個主鍵每10秒鐘返回一個令牌。當在10秒鐘之內(nèi)有請求,一個特殊的通知將會告訴客戶端稍等一下。通常,擁有租約的客戶端將會在幾個毫秒的時間內(nèi)成功設(shè)置數(shù)據(jù)。因此,當?shù)却蛻舳酥卦嚨臅r候,數(shù)據(jù)經(jīng)常已經(jīng)在緩存中了。 |
| 為了說明這一點,我們針對容易造成驚群的主鍵集合收集了一個星期的緩存不命中的記錄。如果沒有租約機制,所有的緩存不命中都會造成數(shù)據(jù)庫查詢率的峰值——17K/s。使用租約機制的時候,數(shù)據(jù)庫查詢率的峰值是1.3K/s。因為我們依據(jù)峰值負載準備數(shù)據(jù)庫,所有租約機制提供了顯著的效率增益。 過期值:當使用租約機制的時候,我們可以最小化某些特定用例下的應(yīng)用等待時間。我們可以通過鑒別返回稍微過期數(shù)據(jù)可以接受的情況進一步減少等待時間。當一個主鍵被刪除的時候,對應(yīng)的值轉(zhuǎn)移到一個保存最近刪除項的數(shù)據(jù)結(jié)構(gòu)中,在被清楚之前將會存活很短的時間。一個get請求可能返回一個租約,或者是一個標記為已過時的數(shù)據(jù)。應(yīng)用可以使用過時的數(shù)據(jù)繼續(xù)轉(zhuǎn)發(fā)處理,而不需要等待從數(shù)據(jù)庫讀取的最新數(shù)據(jù)。經(jīng)驗告訴我們因為緩存數(shù)據(jù)趨向于單調(diào)遞增的數(shù)據(jù)庫快照,大部分應(yīng)用可以在對數(shù)據(jù)不做改變的情況下使用過時數(shù)據(jù)。 ??????????? 圖5:高抖動鍵集合和低抖動鍵集合的每日和每周的工作集 |
| 3.2.2 memcache池 ??????????? 使用memcache做為通用的緩存層要求不同的工作負載分享基礎(chǔ)設(shè)施,盡管它們具有不過的接入模式、內(nèi)存占用和服務(wù)質(zhì)量要求。不同應(yīng)用的工作負載可以產(chǎn)生負干擾,這將會導(dǎo)致命中率下降。 ??????????? 為了適用這些差異,我們將集群的memcached服務(wù)器分割成獨立的池。我們指定一個池(稱作wildcard)為默認池,針對那些放在wildcard中不合適的主鍵提供另外的池。例如,我們可能為頻繁存取但是緩存不命中不耗時的主鍵分配一個小池。我們也可能為那些不頻繁存取但是緩存不命中異常耗時的主鍵分配一個大池。 |
| 圖5展示了兩個不同的項目集合的工作集,一個低抖動,另一個高抖動。工作集通過對每百萬分之一數(shù)據(jù)項采樣所有操作來近似。對于這些數(shù)據(jù)項,我們收集最小、平均和最大數(shù)據(jù)項大小。這些數(shù)據(jù)項大小被加總,然后乘以一百萬來近似工作集。每日和每周工作集的不同指出抖動的總數(shù)。具有不同抖動特征的數(shù)據(jù)項以一種不幸的方式相互影響:那些仍然有價值的低抖動主鍵在那些不再被存取的高抖動主鍵之前被踢出。將這些不同的主鍵放在不同的池中將會阻止這種負干擾,同時使我們可以通過設(shè)置高抖動池的大小來適用緩存不命中的成本。第7章提供了更深入的分析。 [譯者注:工作集定義為在一個特定的時間段內(nèi)一個進程所需要的內(nèi)存] |
| 3.2.3 池內(nèi)的復(fù)制(replication) ??????????? 在某些池內(nèi),我們使用復(fù)制(replication)來改善延遲和memcached服務(wù)器的效率。當(1)應(yīng)用常規(guī)地同時讀取很多主鍵,(2)整個數(shù)據(jù)集集合可以放到一或兩個memcached服務(wù)器中,(3)請求率非常高,超出了單臺服務(wù)器的處理能力的時候,我們選擇復(fù)制池內(nèi)的一類主鍵。 ??????????? 比起進一步劃分主鍵空間,我們更傾向于在實例內(nèi)進行復(fù)制。考慮一個包含100個數(shù)據(jù)項的memcached服務(wù)器,具有對每秒500K請求進行處理的能力。每一個請求查找100個主鍵。在memcached中每個請求查詢100個主鍵與查詢1個主鍵之間開銷的差值是很小的。為了擴展系統(tǒng)來處理1M請求/秒,假如我們增加了第二臺服務(wù)器,將主鍵平均分配到兩臺服務(wù)器上。現(xiàn)在客戶端需要將每個包含100個主鍵的請求分割為兩個并行的包含50個主鍵的請求。結(jié)果兩臺服務(wù)器都仍然不得不處理每秒1M的請求。然后,如果我們復(fù)制所以100個主鍵到兩臺服務(wù)器,一個包含100個主鍵的客戶端請求可以被發(fā)送到任意副本(replica)。這樣將每臺服務(wù)器的負載降到了每秒500K個請求。每一個客戶端依據(jù)自己的IP地址來選擇副本。這種方法需要向所以的副本分發(fā)失效消息來維護一致性。 |
| 3.3 故障處理 ??????????? 無法從memcache中讀取數(shù)據(jù)將會導(dǎo)致后端服務(wù)負載激增,這會導(dǎo)致進一步的連鎖故障。有兩個尺度的故障我們必須解決:(1)由于網(wǎng)絡(luò)或服務(wù)器故障,少量的主機無法接入,(2)影響到集群內(nèi)相當大比例服務(wù)器的廣泛停機事件。如果整個的集群不得不離線,我們轉(zhuǎn)移用戶的web請求到別的集群,這樣將會有效地遷移memcache所有的負載。 ??????????? 對于小范圍的停機,我們依賴一個自動化修復(fù)系統(tǒng)[3]。這些操作不是即時的,需要花費幾分鐘。這么長的持續(xù)時間足夠引發(fā)前面提到的連鎖故障,因此我們引入了一個機制進一步將后端服務(wù)從故障中隔離開來。我們專門準備了少量稱作Gutter的機器來接管少量故障服務(wù)器的責(zé)任。在一個集群中,Gutter的數(shù)量大約為memcached服務(wù)器的1%。 |
| 當memcached客戶端對它的get請求收不到回應(yīng)的時候,這個客戶端就假設(shè)服務(wù)器已經(jīng)發(fā)生故障了,然后向特定的Gutter池再次發(fā)送請求。如果第二個請求沒有命中,那么客戶端將會在查詢數(shù)據(jù)庫之后將適當?shù)逆I-值對插入Gutter機器。在Gutter中的條目會很快過期以避免Gutter失效。Gutter以提供稍微過時的數(shù)據(jù)為代價來限制后端服務(wù)的負載。 ??????????? 注意,這樣的設(shè)計與客戶端在剩下的memcached服務(wù)器重新分配主鍵的方法不同。由于頻繁存取的主鍵分布不均勻,那樣的方法會有連鎖故障的風(fēng)險。例如,一個單獨的主鍵占服務(wù)器請求的20%。承擔(dān)這個頻繁存取的主鍵的服務(wù)器也會過載。通過將負載分流到閑置的服務(wù)器,我們減少了這樣的風(fēng)險。 ??????????? 通常來說,每個失敗的請求都會導(dǎo)致對后端儲存的一次存取,潛在地將會使后端過載。使用Gutter存儲這些結(jié)果,很大部分失敗被轉(zhuǎn)移到對gutter池的存取,因此減少了后端存儲的負載。在實踐中,這個系統(tǒng)每天減少99%的客戶端可見的失敗率,將10%-25%的失敗轉(zhuǎn)化為緩存命中。如果一臺memcached服務(wù)器整個發(fā)生故障,在4分鐘之內(nèi),gutter池的命中率將會普遍增加到35%,經(jīng)常會接近50%。因此對于由于故障或者小范圍網(wǎng)絡(luò)事故造成的一些memcached服務(wù)器不可達的情況,Gutter將會保護后端存儲免于流量激增。 ? |
| 4 Region之內(nèi):復(fù)制(Replication) ??????????? 隨著需求的增長,購買更多的web服務(wù)器和memcached服務(wù)器來擴展集群是誘惑人的。但是幼稚地擴展系統(tǒng)并不能解決所有問題。隨著更多的web服務(wù)器加入來處理增長的用戶流量,高請求率的數(shù)據(jù)項只會變的更流行。隨著memcached服務(wù)器的增加,Incast擁塞也會變的更嚴重。因此我們將web服務(wù)器和memcached服務(wù)器分割為多個前端集群。這些集群與包含數(shù)據(jù)庫的存儲集群一起統(tǒng)稱為region。region架構(gòu)同樣也考慮到更小的故障域和易控制的網(wǎng)絡(luò)配置。我們用數(shù)據(jù)的復(fù)制來換取更獨立的故障域、易控制的網(wǎng)絡(luò)配置和incast擁塞的減少。 ??????????? 這一章分析了分享同一個存儲集群的多個前端集群的影響。特別地,我們說明了允許數(shù)據(jù)跨集群復(fù)制的影響,以及不允許復(fù)制潛在的內(nèi)存效率。 ? |
| 4.1 region內(nèi)的失效 ??????????? 在region中,存儲集群保存數(shù)據(jù)的權(quán)威版本,為了滿足用戶的需求就需要將數(shù)據(jù)復(fù)制到前端集群。存儲集群負責(zé)使緩存數(shù)據(jù)失效來保持前端集群與權(quán)威版本的一致性。做為一個優(yōu)化,當web服務(wù)器修改數(shù)據(jù)后,它也會向所在的集群發(fā)送失效命令,提供針對單用戶請求的讀后寫語義,這樣可以減少本機緩存的存在時間。 ??????????? 圖6:失效流水線 展示那些需要經(jīng)過守護進程(mcsqueal)刪除的主鍵 ??????????? 修改權(quán)威數(shù)據(jù)的SQL語句被改進為包含事務(wù)提交后需要使失效的對應(yīng)的memcache主鍵[7]。我們在所有的數(shù)據(jù)庫上部署了失效守護進程(稱作mcsqueal)。每個守護進程檢查數(shù)據(jù)庫提交的SQL語句,提取任意的刪除命令,并且將刪除命令廣播到region內(nèi)所有的前端集群。圖6展示了這個方法。我們發(fā)現(xiàn)大部分發(fā)出的失效命令并不會造成刪除數(shù)據(jù)的操作,實際上,所有發(fā)出的刪除命令只有4%導(dǎo)致實際的緩存數(shù)據(jù)失效。 ? |
| 減少發(fā)包率:如果mcsqueal可以直接聯(lián)系memcached服務(wù),那么從后端集群到前端集群的發(fā)包率將會高的無法接受。有很多數(shù)據(jù)庫和很多memcached服務(wù)器跨集群邊界通信造成了發(fā)包率的問題。失效守護進程批量處理刪除操作,使用很少的包把操作發(fā)送到每個前段集群運行著mcrouter的指定服務(wù)器。然后mcrouter就從每個批量包中分解出單獨的刪除操作,將失效命令路由到所在前端集群正確的memcached服務(wù)器。通過統(tǒng)計每個包中刪除命令的中位數(shù)可見批處理具有18倍的性能提升。 通過web服務(wù)器發(fā)送失效命令:通過web服務(wù)器廣播失效命令到所有前端服務(wù)器更簡單。很不幸,這個方法存在兩個問題。第一個,因為web服務(wù)器在批處理無效命令時沒有mcsqueal有效率,所以它具有更高的包成本。第二個,當系統(tǒng)性的無效問題出現(xiàn)時,這種方法會無能為力,比如由于配置錯誤造成的刪除命令錯誤路由。過去,這經(jīng)常需要動態(tài)重啟整個memcache基礎(chǔ)設(shè)施,這樣一個緩慢的、破壞性的進程是我們一直想避免的。相反,將失效命令嵌入SQL語句允許mcsqueal簡單的重新執(zhí)行可能已經(jīng)丟掉的或者錯誤路由的失效命令,因為數(shù)據(jù)庫提交存儲有可靠的日志。 表1: 集群復(fù)制或region復(fù)制的決定性因素 [譯者注:動態(tài)重啟(rolling restart)是賽車比賽中的一個術(shù)語。看看F1比賽就會有個直觀的概念,比賽的時候經(jīng)常會出現(xiàn)安全車領(lǐng)著賽車跑兩圈,當安全車離開后出現(xiàn)綠旗,這就是一次rolling start] |
| 4.2 Region池 ??????????? 每個集群依照混合的用戶請求獨立地緩存數(shù)據(jù)。如果用戶請求被隨機的路由到所有可獲得的前端集群,那么所有前端服務(wù)器緩存的數(shù)據(jù)將會大致上一樣。這就允許我們離線維護某個集群,而不會導(dǎo)致緩存命中率下降。過度復(fù)制數(shù)據(jù)會使內(nèi)存沒有效率,特別是對很大的、很少存取的數(shù)據(jù)項。通過使多個前端集群分享同一個memcached服務(wù)器集合,我們就可以減少副本的數(shù)量。我們稱此為region池。 ??????????? 跨集群邊界通信會導(dǎo)致更大的延遲。另外,我們的集群間可獲得帶寬比集群內(nèi)的少40%。復(fù)制用更多的memcached服務(wù)器換取更少的集群間帶寬,低延遲和更好的容錯。對于某一些數(shù)據(jù),放棄副本的好處,每個region一個拷貝,從成本上來說更有效率。擴展memcache的一個主要挑戰(zhàn)是決定某主鍵是應(yīng)該跨前端集群復(fù)制,還是每個region一個副本。當region池發(fā)生故障時,Gutter也會被使用。 |
| 表1總結(jié)了我們應(yīng)用中具有巨大價值的兩類項目。我們將B類型的數(shù)據(jù)移到region池,對于A類型的不做改變。注意,客戶端存取B類型數(shù)據(jù)的頻率比A類型數(shù)據(jù)低一個數(shù)量級。B類型數(shù)據(jù)的低存取率使它成為region池的主要候選者,因為這樣的數(shù)據(jù)不會對集群間帶寬造成不利的影響。B類型數(shù)據(jù)也會占有每個集群wildcard池25%的空間,所以區(qū)域化提供了顯著的存儲效率。然而在A類型的數(shù)據(jù)項的大小是B類型的兩倍,而且存取更頻繁,所以從region的角度考慮,不會將它們放在region池中。目前將數(shù)據(jù)遷移到region池的依據(jù)是基于存取率、數(shù)據(jù)大小和存取用戶數(shù)的人工的啟發(fā)式方法。 |
| 4.3 冷集群熱身 ??????????? 由于存在的集群發(fā)生故障或者進行定期的維護,我們增加新的集群上線,此時緩存命中率會很低,這樣會削弱隔離后端服務(wù)的能力。一個稱作冷集群熱身(Cold Cluster Warmup)的系統(tǒng)可以緩和這種情況,這個系統(tǒng)使“冷集群”(也就是具有空緩存的前端集群)中的客戶端從“熱集群”(也就是具有正常緩存命中率的集群)中檢索數(shù)據(jù)而不是從持久化存儲。這利用到了前面提到的跨前端集群的數(shù)據(jù)復(fù)制。使用這個系統(tǒng)可以使冷集群在幾個小時恢復(fù)到滿負載工作能力而不是幾天。 |
必須注意避免由于競爭條件引發(fā)的不一致。例如,如果冷集群中的一個客戶端對數(shù)據(jù)庫做了更新,另外一個客戶端在熱集群收到失效命令之前檢索到過時數(shù)據(jù),這個數(shù)據(jù)項在冷集群中將會不一致。memcached的刪除命令支持非零的拖延時間,也就是在指定的拖延時間內(nèi)拒絕添加操作。默認情況下,冷集群中所有的刪除命令都有兩秒鐘的拖延時間。當在冷集群中發(fā)生緩存不命中時,客戶端向熱集群重新發(fā)送請求,然后將結(jié)果添加到冷集群中。如果添加失敗就表明數(shù)據(jù)庫中有更新的數(shù)據(jù),因此客戶端將會重新從數(shù)據(jù)庫讀數(shù)據(jù)。刪除命令延遲兩秒鐘以上在理論上來說也是有可能的,但是對于大部分的情況并不會超過兩秒鐘。冷集群熱身運營上的效益遠遠超過少數(shù)緩存不一致所帶來的成本。一旦冷集群的命中率趨于穩(wěn)定,我們就將冷集群熱身系統(tǒng)關(guān)掉,同時效益也就減少了。 5 跨地區(qū):一致性將數(shù)據(jù)中心分布到廣泛的地理位置具有很多優(yōu)勢。第一,將web服務(wù)器靠近終端用戶可以極大地較少延遲。第二,地理位置多元化可以緩解自然災(zāi)害和大規(guī)模電力故障的影響。第三,新的位置可以提供更便宜的電力和其它經(jīng)濟上的誘因。我們通過部署多個region來獲得這些優(yōu)勢。每個region包含一個存儲集群和多個前端集群。我們指定一個region持有主數(shù)據(jù)庫,別的region包含只讀的副本;我們依賴MySQL的復(fù)制機制來保持副本數(shù)據(jù)庫與主數(shù)據(jù)庫的同步。基于這樣的設(shè)計,web服務(wù)器無論訪問本地memcached服務(wù)器還是本地數(shù)據(jù)庫副本的延遲都很低。當擴展到多region的時候,維護memcache和持久化存儲的數(shù)據(jù)一致性成了主要的技術(shù)挑戰(zhàn)。這些挑戰(zhàn)源于一個問題:副本數(shù)據(jù)庫可能滯后于主數(shù)據(jù)庫。
英文原文:Scaling Memcache At Facebook 轉(zhuǎn)自:http://www.linuxeden.com/html/news/20130605/139918_2.html |
轉(zhuǎn)載于:https://www.cnblogs.com/YuanZhaoBest/p/3856478.html
總結(jié)
以上是生活随笔為你收集整理的Facebook 对 Memcache 伸缩性的增强的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 网页上的静止导航脚本
- 下一篇: 从注册流程 分析如何安全退出多个Acti