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