溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶(hù)服務(wù)條款》

怎樣實(shí)踐微信后臺(tái)的海量數(shù)據(jù)冷熱分級(jí)架構(gòu)設(shè)計(jì)

發(fā)布時(shí)間:2021-09-10 19:01:19 來(lái)源:億速云 閱讀:120 作者:柒染 欄目:大數(shù)據(jù)

今天就跟大家聊聊有關(guān)怎樣實(shí)踐微信后臺(tái)的海量數(shù)據(jù)冷熱分級(jí)架構(gòu)設(shè)計(jì),可能很多人都不太了解,為了讓大家更加了解,小編給大家總結(jié)了以下內(nèi)容,希望大家根據(jù)這篇文章可以有所收獲。

微信的后臺(tái)數(shù)據(jù)存儲(chǔ)隨著微信產(chǎn)品特性的演進(jìn),經(jīng)歷了數(shù)次的架構(gòu)改造,才形成如今成熟的大規(guī)模分布式存儲(chǔ)系統(tǒng),有條不紊的管理著由數(shù)千臺(tái)異構(gòu)機(jī)型組成的機(jī)器集群,得以支撐每天千萬(wàn)億級(jí)的訪問(wèn)、鍵值以及 PB 級(jí)的數(shù)據(jù)。

作為以手機(jī)為平臺(tái)的移動(dòng)社交應(yīng)用,微信內(nèi)大部分業(yè)務(wù)生成的數(shù)據(jù)是有共性可言的:數(shù)據(jù)鍵值帶有時(shí)間戳信息,并且單用戶(hù)數(shù)據(jù)隨著時(shí)間在不斷的生成。我們將這類(lèi)數(shù)據(jù)稱(chēng)為基于時(shí)間序的數(shù)據(jù)。比如朋友圈中的發(fā)表,或者移動(dòng)支付的賬單流水等業(yè)務(wù)生成的數(shù)據(jù)都滿(mǎn)足這樣的特征?;跁r(shí)間序的數(shù)據(jù)都天然帶有冷熱分明屬性――這是由手機(jī)的物理特性決定的,它的尺寸有限的屏幕所展示的數(shù)據(jù)只能分屏,通過(guò)手指的滑動(dòng),平滑而又連續(xù)的沿時(shí)間軸依次訪問(wèn)――通常是由最新生成的數(shù)據(jù),慢慢回溯到較早前的數(shù)據(jù)。同時(shí)朋友圈等業(yè)務(wù)都是信息讀擴(kuò)散的應(yīng)用場(chǎng)景,這就意味著它們生成的后臺(tái)數(shù)據(jù)具有讀多寫(xiě)少的鮮明特征。

在微信的實(shí)際應(yīng)用場(chǎng)景中,這類(lèi)數(shù)據(jù)的主要特點(diǎn)包括:數(shù)據(jù)量大、訪問(wèn)量大、重要程度高等。這些特點(diǎn)在現(xiàn)網(wǎng)的實(shí)際運(yùn)營(yíng)過(guò)程中,給我們帶來(lái)了非常大的挑戰(zhàn),主要包括:

  1. 數(shù)據(jù)量大,需求的存儲(chǔ)容量高――基于時(shí)間序的數(shù)據(jù)通常不會(huì)刪除,而是隨著時(shí)間不斷積累,數(shù)據(jù)量達(dá)到 PB 級(jí)別,相應(yīng)需要的存儲(chǔ)空間也與日俱增;

  2. 訪問(wèn)量大,節(jié)日效應(yīng)明顯――基于時(shí)間序的數(shù)據(jù)往往是熱點(diǎn)業(yè)務(wù)生成的數(shù)據(jù),它們的訪問(wèn)量居高不下,基本維持在每分鐘數(shù)十億次的級(jí)別。尤其是在節(jié)日期間,瞬發(fā)訪問(wèn)量更可達(dá)平日的三至五倍;

  3. 重要性高,用戶(hù)感知明顯,數(shù)據(jù)一旦丟失,導(dǎo)致用戶(hù)不能正常使用產(chǎn)品,并因此而轉(zhuǎn)化成的投訴率高。

通過(guò)堆機(jī)器來(lái)橫向擴(kuò)展存儲(chǔ)自然可以應(yīng)對(duì)如上的各種挑戰(zhàn),然而在成本預(yù)算緊張的前提下,機(jī)器數(shù)目是有限的。在這種情況下,基于時(shí)間序的海量數(shù)據(jù)的冷熱分級(jí)架構(gòu)便應(yīng)運(yùn)而生。該架構(gòu)正是為了應(yīng)對(duì)后臺(tái)日益膨脹的這類(lèi)數(shù)據(jù),本著充分利用機(jī)器資源,發(fā)揮各種硬件介質(zhì)特長(zhǎng)的原則,結(jié)合數(shù)據(jù)的冷熱分明、讀多寫(xiě)少的訪問(wèn)特征而開(kāi)發(fā)和設(shè)計(jì)出來(lái)的。它基于數(shù)據(jù)分層的理念,根據(jù)不同時(shí)間段的數(shù)據(jù)在訪問(wèn)熱度和數(shù)據(jù)量上的差異,定制不同的服務(wù)策略,在縱向上擴(kuò)展存儲(chǔ)的邊界。橫向擴(kuò)展存儲(chǔ)是易于理解的,通過(guò)向原集群中增加相同類(lèi)型的機(jī)器――其中必然涉及到一輪歷史數(shù)據(jù)的遷移――最終新舊機(jī)器負(fù)載均衡,彼此之間并無(wú)差異的對(duì)外提供服務(wù)。在這種方案下,數(shù)據(jù)橫向流動(dòng),系統(tǒng)一視同仁的對(duì)待,顯然并無(wú)因地制宜思想的容身之所。而縱向擴(kuò)展存儲(chǔ)的架構(gòu)便提供了這樣一種思路:

對(duì)熱點(diǎn)數(shù)據(jù),數(shù)據(jù)量少,但承擔(dān)的訪問(wèn)流量大,我們當(dāng)然是希望它們能常駐內(nèi)存,因此系統(tǒng)提供了有強(qiáng)一致保證的內(nèi)存層,在應(yīng)對(duì)突發(fā)流量時(shí),也可在不涉及歷史數(shù)據(jù)遷移的前提下,單獨(dú)、動(dòng)態(tài)的快速擴(kuò)展內(nèi)存層。

對(duì)歷史數(shù)據(jù),數(shù)據(jù)存量大,但承擔(dān)的訪問(wèn)量非常有限,我們當(dāng)然是不希望用昂貴的固態(tài)硬盤(pán)來(lái)存儲(chǔ)它們,因此,系統(tǒng)提供了廉價(jià)的機(jī)械盤(pán)層,并且有一套透明的冷數(shù)據(jù)剝離和批量下沉的流程,將存儲(chǔ)層中歷史數(shù)據(jù)源源不斷的抽離到機(jī)械盤(pán)層。

通過(guò)這樣的一種縱向分層、單獨(dú)擴(kuò)展的思路,即為我們系統(tǒng)提供了極大的靈活性,解決了節(jié)日期間存儲(chǔ)層面臨的內(nèi)存瓶頸,以從長(zhǎng)遠(yuǎn)的角度為我們緩解了成本壓力,解決了存儲(chǔ)層面臨的磁盤(pán)容量瓶頸。

當(dāng)然一套成功的大型分布式系統(tǒng)僅有這些是不夠的,還必須包括數(shù)據(jù)多副本復(fù)制策略以及分區(qū)算法等,也要有能應(yīng)對(duì)復(fù)雜的現(xiàn)網(wǎng)運(yùn)營(yíng)環(huán)境的能力。我們結(jié)合各層的服務(wù)特點(diǎn),制訂了相對(duì)應(yīng)的數(shù)據(jù)強(qiáng)一致算法,如內(nèi)存層通過(guò)版本號(hào)控制來(lái)保證與存儲(chǔ)層的完全一致,存儲(chǔ)層通過(guò) Paxos Group 實(shí)現(xiàn)多副本容災(zāi),而機(jī)械盤(pán)層則通過(guò)串行寫(xiě)來(lái)保證。我們同時(shí)也實(shí)現(xiàn)了自己的去中心化的數(shù)據(jù)路由算法,確保了數(shù)據(jù)和流量的均勻分布,并且保證這種特性在橫向擴(kuò)展后依然成立。

通過(guò)如上工作的努力,環(huán)環(huán)相扣,我們的基于時(shí)間序的海量數(shù)據(jù)的冷熱分層架構(gòu)成功的應(yīng)對(duì)了 PB 級(jí)數(shù)據(jù)、千億級(jí)訪問(wèn)以及萬(wàn)億級(jí)鍵值帶來(lái)的挑戰(zhàn)。

系統(tǒng)設(shè)計(jì)

數(shù)據(jù)模型

本文提及的海量數(shù)據(jù)的冷熱分級(jí)架構(gòu)是專(zhuān)門(mén)服務(wù)于基于時(shí)間序的數(shù)據(jù),它們主要特征為:

a). 數(shù)據(jù)鍵值帶有時(shí)間戳信息 ;

b). 單用戶(hù)數(shù)據(jù)隨著時(shí)間在不斷的生成。

我們?cè)O(shè)計(jì)的架構(gòu)強(qiáng)依賴(lài)于特性 a),各個(gè)環(huán)節(jié)基本上是依賴(lài)于鍵值中的時(shí)間戳來(lái)分發(fā)數(shù)據(jù)或者進(jìn)行數(shù)據(jù)排序的。至于鍵值中的時(shí)間戳如何生成、全局是否維持統(tǒng)一時(shí)間、如何維持等則不在本文的討論范圍,通常這由前端的業(yè)務(wù)特性以及后臺(tái)的時(shí)間服務(wù)器策略決定的。

而特性 b) 則保證了本架構(gòu)的必要性、實(shí)用性。如果數(shù)據(jù)規(guī)模有限,以用戶(hù)的賬戶(hù)信息舉例,它就像我們?nèi)粘I钪械膽?hù)口本,它只有一份,對(duì)單用戶(hù)而言不會(huì)新增。則我們通常用固定的機(jī)器集群存儲(chǔ)就可以,并且鮮有變更。而我們要處理的是用戶(hù)的日記本、或者記賬簿,它們每天都在不斷生成新數(shù)據(jù)。

我們以現(xiàn)網(wǎng)某個(gè)集群的實(shí)例情況舉例,說(shuō)明下此類(lèi)業(yè)務(wù)數(shù)據(jù)有如下的特點(diǎn):

1.、數(shù)據(jù)量大,PB 級(jí)數(shù)據(jù),萬(wàn)億級(jí)鍵值,并且在源源不斷的生成中,然而新生成的數(shù)據(jù)相較于歷史存量數(shù)據(jù)占比小。下圖展示了該集群數(shù)據(jù)在各時(shí)間段的一個(gè)占比情況。

怎樣實(shí)踐微信后臺(tái)的海量數(shù)據(jù)冷熱分級(jí)架構(gòu)設(shè)計(jì)

2、訪問(wèn)量大,峰值可達(dá)每分鐘數(shù)十億次訪問(wèn),尤其是在節(jié)日期間,用戶(hù)高漲的熱情更可以轉(zhuǎn)化成平日三至五倍的訪問(wèn)量。同時(shí)具有冷熱分明、讀多寫(xiě)少 (讀寫(xiě)比例甚至可達(dá) 100:1) 的訪問(wèn)特征,比如節(jié)日期間倍增的訪問(wèn)通常是對(duì)節(jié)日期間生成的新增數(shù)據(jù)的訪問(wèn)。下圖展示了該集群訪問(wèn)在各時(shí)間段的一個(gè)占比情況。

怎樣實(shí)踐微信后臺(tái)的海量數(shù)據(jù)冷熱分級(jí)架構(gòu)設(shè)計(jì)

3、數(shù)據(jù)安全性要求高,這類(lèi)數(shù)據(jù)通常是用戶(hù)感知敏感數(shù)據(jù),一旦丟失,轉(zhuǎn)化成的用戶(hù)投訴率高。

系統(tǒng)架構(gòu)

系統(tǒng)由三個(gè)層次組成,如圖所求,分別是內(nèi)存層、存儲(chǔ)層(熱數(shù)據(jù)存儲(chǔ)層)以及機(jī)械磁盤(pán)層(冷數(shù)據(jù)存儲(chǔ)層)。從時(shí)間軸上看,它們服務(wù)的數(shù)據(jù)由熱至冷。如下圖所示:

怎樣實(shí)踐微信后臺(tái)的海量數(shù)據(jù)冷熱分級(jí)架構(gòu)設(shè)計(jì)

從客戶(hù)端的角度看,三層都是并列的,客戶(hù)端都會(huì)直接的與某層中的某臺(tái)機(jī)器發(fā)生通信。具體的區(qū)別點(diǎn)在于,內(nèi)存層和機(jī)械磁盤(pán)層對(duì)客戶(hù)端而言是只讀的。所有的寫(xiě)都是由客戶(hù)端直接寫(xiě)向存儲(chǔ)層。我們將去中心化的配置分發(fā)到客戶(hù)端機(jī)器上,配置的類(lèi)型包括內(nèi)存層路由、存儲(chǔ)層路由以及其它元數(shù)據(jù),客戶(hù)端根據(jù)配置中的時(shí)間分隔點(diǎn)以及流量比例,來(lái)決定將當(dāng)前的讀請(qǐng)求分發(fā)到內(nèi)存層還是存儲(chǔ)層的具體機(jī)器上。配置支持快速分發(fā)和動(dòng)態(tài)加載,可以在秒級(jí)實(shí)現(xiàn)更新。

機(jī)械磁盤(pán)層的路由對(duì)客戶(hù)端而言是透明的,存儲(chǔ)層保存了下沉到機(jī)械磁盤(pán)層的數(shù)據(jù)鏈接,鏈接包含了文件編號(hào)、內(nèi)部偏移和大小,而客戶(hù)端對(duì)此是不知情的。當(dāng)已下沉數(shù)據(jù)的讀請(qǐng)求分發(fā)到存儲(chǔ)層機(jī)器上時(shí),存儲(chǔ)層會(huì)計(jì)算出該數(shù)據(jù)各副本在冷數(shù)據(jù)存儲(chǔ)層對(duì)應(yīng)的機(jī)器地址,然后將它和文件鏈接一起回復(fù)給客戶(hù)端??蛻?hù)端再按照隨機(jī)的策略在多副本之間選擇一份讀取,從這個(gè)角度看,冷數(shù)據(jù)存儲(chǔ)層對(duì)客戶(hù)端而言更像個(gè)遠(yuǎn)程文件系統(tǒng),而 inode 信息和路由表是放在熱數(shù)據(jù)存儲(chǔ)層的。

下面我們?cè)僭敿?xì)的分析各層的設(shè)計(jì)策略。

內(nèi)存層

內(nèi)存層從表現(xiàn)上更像是一個(gè)緩存代理,然而普通的緩存在處理數(shù)據(jù)有效性上是乏力的。常見(jiàn)的策略如寫(xiě)時(shí)淘汰,每次寫(xiě)存儲(chǔ)層之前,都先清理掉緩存中相應(yīng)的數(shù)據(jù),確保失效。然而數(shù)據(jù)在緩存中通常也是多副本的,這個(gè)方案即無(wú)法處理網(wǎng)絡(luò)分區(qū)錯(cuò)誤,并且寫(xiě)時(shí)淘汰也會(huì)產(chǎn)生多次 RPC 請(qǐng)求,過(guò)份的消耗系統(tǒng)資源。另外一種常見(jiàn)策略是有限的數(shù)據(jù)一致性,即過(guò)時(shí)淘汰的策略。在將數(shù)據(jù)寫(xiě)入緩存時(shí),會(huì)附帶一個(gè)有效時(shí)間,在這個(gè)有效期內(nèi),該數(shù)據(jù)一直被認(rèn)為是正確的,并不關(guān)心真實(shí)情況是如何的。這種緩存只能應(yīng)用于對(duì)數(shù)據(jù)實(shí)時(shí)性要求不高的服務(wù)。對(duì)微信的敏感業(yè)務(wù)而言,我們更需要能保證數(shù)據(jù)強(qiáng)一致的分布式緩存。

我們通過(guò)版本號(hào)來(lái)實(shí)現(xiàn)了這一目的。我們?yōu)榫彺嬷械拿恳环輸?shù)據(jù)都維持了一份版本號(hào),存儲(chǔ)層中相應(yīng)的也有一份。只有當(dāng)緩存中的版本號(hào)與存儲(chǔ)層的版本號(hào)達(dá)到一致時(shí),才會(huì)認(rèn)為緩存中的數(shù)據(jù)是有效的。所以,客戶(hù)端每次對(duì)內(nèi)存層的讀請(qǐng)求,都會(huì)由緩存層相應(yīng)的產(chǎn)生一次讀請(qǐng)求發(fā)到存儲(chǔ)層。在一次 RPC 請(qǐng)求中完成有效性的識(shí)別以及過(guò)期數(shù)據(jù)的更新。

怎樣實(shí)踐微信后臺(tái)的海量數(shù)據(jù)冷熱分級(jí)架構(gòu)設(shè)計(jì)

從直覺(jué)上看,采用這種方案的強(qiáng)一致緩存并沒(méi)有降低存儲(chǔ)層的訪問(wèn)壓力。因?yàn)榭蛻?hù)端對(duì)緩存層的請(qǐng)求,與緩存層對(duì)存儲(chǔ)層的請(qǐng)求是 1:1 的。然而這個(gè)方案點(diǎn)的關(guān)鍵在于,我們成功的疏解了存儲(chǔ)層的內(nèi)存瓶頸。將存儲(chǔ)層緩存數(shù)據(jù)的功能,轉(zhuǎn)移到緩存層的內(nèi)存上。我們現(xiàn)在對(duì)存儲(chǔ)層的要求就是能夠盡量的緩存更多的版本號(hào),提供高效的版本號(hào)訪問(wèn)能力就可以了。從這種意義上來(lái)看,這個(gè)強(qiáng)一致性緩存就是存儲(chǔ)層內(nèi)存的延伸。因此,我們將它稱(chēng)為內(nèi)存層。它的優(yōu)勢(shì)在于可動(dòng)態(tài)的調(diào)整流量比例,并且可以在訪問(wèn)高峰期快速的擴(kuò)容。后面的章節(jié)我們也描述了如何通過(guò)工程手段優(yōu)化版本號(hào)交互帶來(lái)的資源消耗。

為了系統(tǒng)的健壯性,一些異常情況也是需要考慮的,如果一臺(tái)內(nèi)存層機(jī)器突然離線,會(huì)有數(shù)十 G 的緩存數(shù)據(jù)失效,我們當(dāng)然不會(huì)希望這數(shù)十 G 數(shù)據(jù)的壓力,會(huì)全部的落到一臺(tái)存儲(chǔ)機(jī)器的磁盤(pán)上。――這無(wú)疑會(huì)引起系統(tǒng)的抖動(dòng)。因此,我們按照組的方式來(lái)部署了內(nèi)存層。每組有多臺(tái)機(jī)器。一份數(shù)據(jù)可能在這多臺(tái)機(jī)器內(nèi)有多個(gè)副本??蛻?hù)端通過(guò)隨機(jī)的次序訪問(wèn)這些機(jī)器。這樣就盡力避免了單結(jié)點(diǎn)失效對(duì)整個(gè)系統(tǒng)的影響。

我們?cè)趦?nèi)存層中設(shè)計(jì)了簡(jiǎn)單、輕量的支持變長(zhǎng)數(shù)據(jù)的緩存結(jié)構(gòu)。每臺(tái)機(jī)器包含數(shù)十條 LRU 鏈,每條鏈都是一個(gè)共享內(nèi)存形式的一維數(shù)組。所有的數(shù)據(jù)都追加寫(xiě)在數(shù)組的最新位置,到尾部后就從頭開(kāi)始循環(huán)。自然,這樣的結(jié)構(gòu)需要一個(gè)索引來(lái)記錄數(shù)據(jù)的位置。這種方式固然浪費(fèi)一些內(nèi)存空間,但避免了內(nèi)存的動(dòng)態(tài)分配。

存儲(chǔ)層

存儲(chǔ)層在整個(gè)系統(tǒng)架構(gòu)中處于核心的位置。內(nèi)存層和機(jī)器硬盤(pán)層都依賴(lài)于它的實(shí)現(xiàn)。前文提及,提供高效輕量的版本號(hào)訪問(wèn)能力是強(qiáng)一致內(nèi)存層實(shí)現(xiàn)的關(guān)鍵。同時(shí),源源不斷的將冷數(shù)據(jù)下沉到機(jī)械硬盤(pán)層的需求,就暗示了在存儲(chǔ)層必須有這樣一種特性:冷數(shù)據(jù)是易于從所有數(shù)據(jù)中剝離,并且收集的。――這樣就意味著,如果在存儲(chǔ)層中數(shù)據(jù)是平坦的,冷熱數(shù)據(jù)混雜在一起,那么我們?cè)诔殡x冷數(shù)據(jù)的時(shí)候,就要把硬盤(pán)中所有的數(shù)據(jù)遍歷一輪,無(wú)疑會(huì)消耗比較多的系統(tǒng)資源。

因此我們采用了 lsm-tree 算法來(lái)實(shí)現(xiàn)這一需求。該算法和 B+ 樹(shù)一樣是種建立索引的技術(shù)。不同的是它基于多組件 (C0\C1 等組件),通過(guò)延遲提交和歸并排序的方式,將 B+ 樹(shù)的隨機(jī) IO 轉(zhuǎn)變成了內(nèi)存操作和順序 IO。在我們的訪問(wèn)模型下,所有的寫(xiě)都是熱點(diǎn)數(shù)據(jù),只會(huì)提交到 C0 組件。然后在適當(dāng)?shù)臅r(shí)機(jī),同 C1 組件中的數(shù)據(jù)進(jìn)行多路歸并排序。通過(guò)該算法,我們可以同時(shí)實(shí)現(xiàn)數(shù)據(jù)分層和數(shù)據(jù)有序的目的。

怎樣實(shí)踐微信后臺(tái)的海量數(shù)據(jù)冷熱分級(jí)架構(gòu)設(shè)計(jì)

Leveldb 是 Google 公司開(kāi)源的存儲(chǔ)引擎庫(kù),它正是基于 lsm-tree 算法的思想開(kāi)發(fā)出來(lái)的。因此,我們復(fù)用了它成熟的數(shù)據(jù)結(jié)構(gòu)組件,如日志格式、數(shù)據(jù)文件格式、內(nèi)存表格式等。然而它其中的一些運(yùn)行時(shí)策略,卻會(huì)給我們的現(xiàn)網(wǎng)運(yùn)營(yíng)帶來(lái)麻煩。比如說(shuō)運(yùn)行時(shí)不受限的 compact 策略、數(shù)據(jù)文件索引的懶加載等,會(huì)觸發(fā)不可控的讀盤(pán),造成服務(wù)的抖動(dòng);同時(shí)大量的動(dòng)態(tài)內(nèi)存分配也會(huì)對(duì)機(jī)器的內(nèi)存使用帶來(lái)一定不可控的因素。因此,我們拋棄了這些運(yùn)行時(shí)行為,定義了自己的管理策略,使系統(tǒng)變得更加可控。同時(shí),我們利用不同數(shù)據(jù)的訪問(wèn)差異,對(duì)冷、熱數(shù)據(jù)的存儲(chǔ)進(jìn)行了各自的定制,按照時(shí)間段定義按塊壓縮的粒度、索引的粒度等,行之有效的調(diào)和了 CPU、內(nèi)存、磁盤(pán)容量、磁盤(pán) IO 等系統(tǒng)資源之間的轉(zhuǎn)換關(guān)系。

冷數(shù)據(jù)的鏈接和冷集群的路由表,都是記錄在存儲(chǔ)層中而對(duì)前端不可見(jiàn)的。具體的設(shè)計(jì)思想,我們?cè)谙鹿?jié)中詳述。

機(jī)械硬盤(pán)層

機(jī)械硬盤(pán)容量雖大,但是 IO 性能低下,故障率高。一種常見(jiàn)的思路是冷數(shù)據(jù)存儲(chǔ)層獨(dú)立與熱數(shù)據(jù)存儲(chǔ)層,而對(duì)客戶(hù)端直接可見(jiàn)――客戶(hù)端持有一份冷數(shù)據(jù)存儲(chǔ)層的路由,并且獨(dú)自路由――這無(wú)疑是種簡(jiǎn)單、易于理解的方案,但是在我們的應(yīng)用場(chǎng)景中面臨著兩個(gè)問(wèn)題:無(wú)法精確防空以及加劇機(jī)械硬盤(pán)層的 IO 緊張。

定義 TB 訪問(wèn)量為每 TB 數(shù)據(jù)的每秒的訪問(wèn)次數(shù)。在我們的應(yīng)用場(chǎng)景中,每 TB 歷史數(shù)據(jù)的實(shí)際訪問(wèn)量設(shè)為 N,則機(jī)械硬盤(pán)的服務(wù)能力僅為 N 的一半。如果冷數(shù)據(jù)存儲(chǔ)層獨(dú)立,則它需要自己維持所有的數(shù)據(jù)索引,而內(nèi)存容量不足以支持?jǐn)?shù)十 T 數(shù)據(jù)的索引,只能將索引落盤(pán),則每次對(duì)數(shù)據(jù)的讀取都要帶來(lái)兩次隨機(jī)讀盤(pán)。因此,我們將冷數(shù)據(jù)索引以及冷數(shù)據(jù)存儲(chǔ)層的路由表,都放到了熱數(shù)據(jù)存儲(chǔ)層中,而對(duì)前端不可見(jiàn)。

為了容災(zāi),我們必須為每份數(shù)據(jù)存儲(chǔ)多份副本。如果采用雙副本方案,則系統(tǒng)需要冗余 50% 的訪問(wèn)能力,以應(yīng)對(duì)另外一份副本失效的情況,在 io 瓶頸的前提下,這種方案是不可取的。因此我們采用了三副本方案,只要冗余三分之一的能力。每份副本分布在不同的園區(qū),可以實(shí)現(xiàn)園區(qū)級(jí)的容災(zāi)。

怎樣實(shí)踐微信后臺(tái)的海量數(shù)據(jù)冷熱分級(jí)架構(gòu)設(shè)計(jì)

由于機(jī)械盤(pán)容量大、計(jì)算能力差,我們采用 NO RAID 的方式組織了盤(pán)組。為了更好的實(shí)現(xiàn)單盤(pán)失效導(dǎo)致數(shù)據(jù)丟失的故障的災(zāi)后恢復(fù),我們實(shí)現(xiàn)了同組三臺(tái)機(jī)器在盤(pán)級(jí)別數(shù)據(jù)的完全相同。為了達(dá)到盤(pán)級(jí)別的負(fù)載均衡,我們通過(guò)預(yù)計(jì)算路由、硬編碼的方式,實(shí)現(xiàn)了 (數(shù)據(jù) ->機(jī)器 ->盤(pán) ->文件) 的單調(diào)映射,由數(shù)據(jù)的鍵值可以直接定位到盤(pán)的索引以及文件的編號(hào)。

怎樣實(shí)踐微信后臺(tái)的海量數(shù)據(jù)冷熱分級(jí)架構(gòu)設(shè)計(jì)

作為機(jī)械硬盤(pán)層的補(bǔ)充,一個(gè)冷數(shù)據(jù)下沉的模塊是必須的,它作為冷數(shù)據(jù)存儲(chǔ)層的唯一 Writer,我們通過(guò)兩階段提交的方式確保了下沉過(guò)程的透明性,通過(guò)控制流程發(fā)起時(shí)機(jī)保證資源使用不影響現(xiàn)網(wǎng)服務(wù),通過(guò)預(yù)占位、串行寫(xiě)入的方式,確保了數(shù)據(jù)在冷數(shù)據(jù)存儲(chǔ)層文件級(jí)別的完全一致。

數(shù)據(jù)強(qiáng)一致性保證

業(yè)務(wù)要求系統(tǒng)必須保證在數(shù)據(jù)的多份副本之間保持強(qiáng)一致性。――這是一個(gè)歷久彌新的挑戰(zhàn)。我們將分內(nèi)存層、存儲(chǔ)層、機(jī)械硬盤(pán)層分別來(lái)考慮數(shù)據(jù)的強(qiáng)一致性維持。

強(qiáng)一致緩存

正如前文描述,內(nèi)存層作為一種強(qiáng)一致性分布式緩存,它完全是向存儲(chǔ)層對(duì)齊的,自身無(wú)法判別數(shù)據(jù)有效性,本身多副本之間也沒(méi)有交互的必要。它對(duì)前端而言是只讀的,所有的寫(xiě)請(qǐng)求并不通過(guò)它,它只能算是存儲(chǔ)層中數(shù)據(jù)的一個(gè)視圖。所以它對(duì)前端數(shù)據(jù)有效性的承諾完全是依賴(lài)于存儲(chǔ)層的正確性的。

Paxos Group

我們基于 Paxos Group 實(shí)現(xiàn)了存儲(chǔ)層的數(shù)據(jù)一致性,通過(guò)采用無(wú)租約的方式,使得系統(tǒng)在保證強(qiáng)一致性的前提下達(dá)到了最大的可用性。Paxos 算法是由 Lesile Lamport 在論文中首提的,它唯一的作用是在多個(gè)參與者之間唯一的確定一個(gè)常量值。――這點(diǎn)同分布式存儲(chǔ)沒(méi)有直接關(guān)聯(lián)的。我們?cè)?Paxos 算法的基礎(chǔ)上,設(shè)計(jì)出基于消息驅(qū)動(dòng)的 Paxos Log 組件――每一條操作日志都要 Paxos 算法來(lái)確定,再進(jìn)一步實(shí)現(xiàn)了基于 Paxos Log 的強(qiáng)一致性讀寫(xiě)。

Paxos Group 因?yàn)椴捎昧藷o(wú)主模型,組內(nèi)所有機(jī)器在任一時(shí)刻都處于相同的地位。Paxos 算法本質(zhì)是個(gè)多副本同步寫(xiě)算法,當(dāng)且僅當(dāng)系統(tǒng)中的多數(shù)派都接受相同值后,才會(huì)返回寫(xiě)成功。因此任意單一節(jié)點(diǎn)的失效,都不會(huì)出現(xiàn)系統(tǒng)的不可用。

強(qiáng)一致性寫(xiě)協(xié)議的主要問(wèn)題來(lái)源于 Paxos 算法本身,因?yàn)橐_保數(shù)據(jù)被系統(tǒng)內(nèi)的多數(shù)派接受,需要進(jìn)行多階段的交互。我們采用如下的方法,解決了 paxos 算法寫(xiě)過(guò)程中出現(xiàn)的問(wèn)題:基于 fast accept 協(xié)議優(yōu)化了寫(xiě)算法,降低了寫(xiě)盤(pán)量以及協(xié)議消息發(fā)送、接收次數(shù),最終實(shí)現(xiàn)了寫(xiě)耗時(shí)和失敗的降低;基于隨機(jī)避讓、限制單次 Paxos 寫(xiě)觸發(fā) Prepare 的次數(shù)等方法,解決了 Paxos 中的活鎖問(wèn)題。

強(qiáng)一致性讀協(xié)議本身和 Paxos 算法并沒(méi)有太大的關(guān)系,只要確認(rèn)多副本之間的多數(shù)派,即可獲取到最新的數(shù)據(jù)。我們通過(guò)廣播的方式獲取到集群中多數(shù)機(jī)器(包含自身)的 paxos log 的狀態(tài),然后判斷本機(jī)數(shù)據(jù)的有效性。

當(dāng)系統(tǒng)中的單機(jī)節(jié)點(diǎn)失效,數(shù)據(jù)完全丟失的時(shí)候――這種情況是可以算是 Paxos 算法的盲區(qū),因?yàn)樵撍惴ɑ谒械膮⑴c者都不會(huì)違背自己曾經(jīng)的承諾,即拜占庭失敗而導(dǎo)致的數(shù)據(jù)不一致。――而這種情況在現(xiàn)網(wǎng)運(yùn)營(yíng)中可謂是常態(tài),因此,我們引入了 Learner Only 模式。在該模式下故障機(jī)只接收已提交的數(shù)據(jù),而不參與 Paxos 協(xié)議的寫(xiě)過(guò)程,意即不會(huì)因數(shù)據(jù)丟失而違背任何承諾。然后通過(guò)異步 catch up 和全量數(shù)據(jù)校驗(yàn)快速?gòu)钠渌北局谢謴?fù)數(shù)據(jù)。

為了防止多節(jié)點(diǎn)同時(shí)失效,我們將數(shù)據(jù)的多副本分布在不同園區(qū)的機(jī)器上。園區(qū)是同一個(gè)城市不同數(shù)據(jù)中心的概念。如此,我們的結(jié)構(gòu)足以應(yīng)對(duì)單數(shù)據(jù)中心完全隔離級(jí)別的災(zāi)難。

串行寫(xiě)入

因?yàn)閷?duì)客戶(hù)端透明,冷數(shù)據(jù)下沉流程作為機(jī)械硬盤(pán)層的唯一寫(xiě)者,則該層的數(shù)據(jù)一致性是易于實(shí)現(xiàn)的。我們通過(guò)三副本串行寫(xiě)入、全部提交才算成功的方式來(lái)實(shí)現(xiàn)了多副本之間的數(shù)據(jù)一致性。

作為補(bǔ)充,冷數(shù)據(jù)集群為數(shù)據(jù)塊增加了 CRC 校驗(yàn)和一致性恢復(fù)隊(duì)列,當(dāng)單機(jī)數(shù)據(jù)不可用 (丟失或者損壞) 時(shí),首先客戶(hù)端會(huì)跳轉(zhuǎn)到其它備份中讀 (三機(jī)同時(shí)對(duì)外提供讀服務(wù)),一致性恢復(fù)隊(duì)列會(huì)異步的從其它備份數(shù)據(jù)塊中恢復(fù)本機(jī)數(shù)據(jù)。

因?yàn)椴捎昧?No Raid 方式組織的盤(pán)組,并且同組機(jī)器間盤(pán)級(jí)別數(shù)據(jù)文件一致,在單盤(pán)故障引發(fā)數(shù)據(jù)丟失時(shí),只要從其它機(jī)器相同序盤(pán)中傳輸數(shù)據(jù)文件即可。

數(shù)據(jù)分區(qū)

靜態(tài)映射表

數(shù)據(jù)分區(qū)的主要目的是為了確保同層機(jī)器間的負(fù)載均衡,并且當(dāng)機(jī)器規(guī)模發(fā)生變化后,在最終仍然可以達(dá)到負(fù)載均衡的一種狀態(tài)。

經(jīng)典的一致性哈希算法的初衷是為了健壯分布式緩存,基于運(yùn)行時(shí)動(dòng)態(tài)的計(jì)算哈希值和虛擬節(jié)點(diǎn)來(lái)進(jìn)行尋址。數(shù)據(jù)存儲(chǔ)與分布式緩存的不同在于,存儲(chǔ)必須保證數(shù)據(jù)映射的單調(diào)性,而緩存則無(wú)此要求,所以經(jīng)典的一致性哈希通常會(huì)使用機(jī)器 IP 等作為參數(shù)來(lái)進(jìn)行哈希,這樣造成的結(jié)果一方面是數(shù)據(jù)的落點(diǎn)時(shí)而發(fā)生改變,一方面是負(fù)載通常不均衡。因此我們改造了此算法。

我們通過(guò)預(yù)計(jì)算虛擬節(jié)點(diǎn)隨機(jī)數(shù)的方法,生成了割環(huán)點(diǎn)同實(shí)體機(jī)器之間的映射表。該映射表最多可支持一千組的集群規(guī)模,滿(mǎn)足在任意組數(shù)情況下,實(shí)體機(jī)器間割段長(zhǎng)度維持差異在 2% 以?xún)?nèi);并且增加任意組數(shù) (總組數(shù)上限不超過(guò)一千組),變動(dòng)后的實(shí)體機(jī)器間的割段長(zhǎng)度依然維持差異在 2% 以?xún)?nèi)。我們將此映射表硬編碼,在運(yùn)行時(shí)避免了計(jì)算的過(guò)程,數(shù)據(jù)根據(jù)鍵值哈希值尋址時(shí),只要經(jīng)過(guò)一次二分查找即可獲取到對(duì)應(yīng)的實(shí)體機(jī)器的編號(hào)。我們?cè)趦?nèi)存層、存儲(chǔ)層以及機(jī)械硬盤(pán)層都采用了這個(gè)映射表,保證了數(shù)據(jù)在各層路由算法的一致。在工程實(shí)現(xiàn)方面,我們可以合理使用這個(gè)特性來(lái)批量合并請(qǐng)求,以降低資源消耗,這在稍后的章節(jié)會(huì)有詳細(xì)描述。

組內(nèi)均衡

組是數(shù)據(jù)分區(qū)的獨(dú)立單元,是虛擬節(jié)點(diǎn)對(duì)應(yīng)的實(shí)體單位。組之間是互相獨(dú)立的。每組由多臺(tái)物理機(jī)器組成,這是 Paxos Group 生效的基本單位。一份數(shù)據(jù)包括的多份副本分別散落在組內(nèi)的各臺(tái)機(jī)器上。為了在組內(nèi)機(jī)器上保證負(fù)載均衡,我們同樣設(shè)計(jì)了一套算法,規(guī)定了數(shù)據(jù)副本之間的訪問(wèn)優(yōu)先級(jí),前端會(huì)依優(yōu)先級(jí)逐一的請(qǐng)求數(shù)據(jù),只要成功獲取,即中斷這個(gè)過(guò)程。然后我們?cè)賹⒏北景磧?yōu)先級(jí)均勻的散落在組內(nèi)機(jī)器上,如此即可實(shí)現(xiàn)組內(nèi)負(fù)載的均衡。

數(shù)據(jù)遷移

靜態(tài)映射表是非常靈活的,在不達(dá)到組數(shù)上限的情況下,可以任意的增加一組或者多組機(jī)器。當(dāng)然這個(gè)過(guò)程中一些數(shù)據(jù)的路由映射發(fā)生了改變,則就涉及到了歷史數(shù)據(jù)的挪騰。為了在挪騰的過(guò)程中不影響服務(wù),保證數(shù)據(jù)依然可讀可寫(xiě),我們開(kāi)發(fā)出了對(duì)前端透明的,基于遷移標(biāo)志位,通過(guò)數(shù)據(jù)雙寫(xiě)和異步挪數(shù)據(jù)的方式實(shí)現(xiàn)的安全的、可回退的數(shù)據(jù)遷移流程。

最小不變塊

存儲(chǔ)層和機(jī)械硬盤(pán)層通過(guò)冷數(shù)據(jù)鏈接耦合在了一起。因?yàn)閮蓪邮褂昧讼嗤挠成浔?,那么?dāng)存儲(chǔ)層因擴(kuò)容而發(fā)生遷移時(shí),那么冷數(shù)據(jù)鏈接無(wú)疑也要重新尋址,進(jìn)行一輪重新定位。如果我們以單鍵值為粒度記錄冷數(shù)據(jù)鏈接和進(jìn)行冷數(shù)據(jù)下沉,那么在萬(wàn)億鍵值的語(yǔ)境下,效率無(wú)疑是低下。因此我們?cè)O(shè)計(jì)了最小不變塊的算法,通過(guò)兩階段哈希,使用中間的哈希桶聚集數(shù)據(jù),將數(shù)據(jù)鍵值和冷數(shù)據(jù)存儲(chǔ)層的機(jī)器路由隔離開(kāi)來(lái)。通過(guò)該算法,我們可以實(shí)現(xiàn):批量的轉(zhuǎn)存冷數(shù)據(jù)、熱數(shù)據(jù)存儲(chǔ)層批量的以塊 (block) 為單位記錄冷數(shù)據(jù)鏈接、當(dāng)熱數(shù)據(jù)存儲(chǔ)層發(fā)生擴(kuò)容時(shí),塊 (block) 內(nèi)的數(shù)據(jù)不因擴(kuò)容被打散掉,而可以整體的遷移到新目標(biāo)機(jī)上。

工程實(shí)現(xiàn)

糟糕的工程實(shí)現(xiàn)可以毀掉一個(gè)完美的系統(tǒng)設(shè)計(jì),因此,如何在工程實(shí)現(xiàn)的過(guò)程中,通過(guò)技術(shù)的手段,提升系統(tǒng)的表現(xiàn),同樣值得重視。

高效緩存

內(nèi)存層的設(shè)計(jì)嚴(yán)重依賴(lài)存儲(chǔ)層數(shù)據(jù)版本號(hào)的高效獲取,那自然是版本號(hào)請(qǐng)求全落在內(nèi)存中就可以了。因此,針對(duì)這種情況我們?yōu)槎ㄩL(zhǎng)的版本號(hào)設(shè)計(jì)了一套極簡(jiǎn)的、輕量的、行之有效的緩存――內(nèi)存容量不足以支撐版本號(hào)全緩存。

怎樣實(shí)踐微信后臺(tái)的海量數(shù)據(jù)冷熱分級(jí)架構(gòu)設(shè)計(jì)

它的數(shù)據(jù)結(jié)構(gòu)只是一個(gè)二維數(shù)組,一維用來(lái)構(gòu)建 hash 鏈,一維用來(lái)實(shí)現(xiàn) LRU 鏈。每次讀或者寫(xiě)都需要通過(guò)數(shù)組內(nèi)數(shù)據(jù)的挪動(dòng),來(lái)進(jìn)行更新。如此一來(lái),我們就通過(guò)千萬(wàn)級(jí)數(shù)目的 LRU 鏈群,實(shí)現(xiàn)了緩存整體的 LRU 淘汰。它具有定長(zhǎng),可共享內(nèi)存搭載,進(jìn)程重啟不丟失、內(nèi)存使用率高等優(yōu)點(diǎn)。

批量操作

對(duì)系統(tǒng)服務(wù)器而言,前端訪問(wèn)過(guò)來(lái)的某個(gè)請(qǐng)求,其對(duì)應(yīng)的邏輯操作都是串行的,我們自然可以梳理這個(gè)串行流程中的 CPU 消耗點(diǎn)進(jìn)行優(yōu)化。然而當(dāng)主要的瓶頸被逐漸的消滅掉后,CPU 消耗點(diǎn)變得分散,優(yōu)化效果就變得微乎其微了。因此,我們只能尋找其它突破點(diǎn)。

我們發(fā)現(xiàn)在存儲(chǔ)引擎、一致性協(xié)議算法的實(shí)現(xiàn)流程中,邏輯操作步驟多,涉及到網(wǎng)絡(luò)交互,硬盤(pán)讀寫(xiě)等過(guò)程。因此,我們決定合并不同請(qǐng)求中的相同步驟,實(shí)現(xiàn)批量化操作,極大的優(yōu)化了 CPU 消耗。

合并的代價(jià)即是耗時(shí)略有增加,我們通過(guò)快慢分離,只針對(duì)熱點(diǎn)數(shù)據(jù)請(qǐng)求中的邏輯操作進(jìn)行合并,去掉了耗時(shí)中的不穩(wěn)定因子,減少了耗時(shí)抖動(dòng)。

請(qǐng)求合并

既然單機(jī)的邏輯操作性能已經(jīng)得到了極大的提升,那么前后端的網(wǎng)絡(luò)交互階段,包括接入層的打包解包、協(xié)議處理等環(huán)節(jié),成為了資源的主要消耗點(diǎn)。參考批量操作的經(jīng)驗(yàn),我們同樣使用批量化的技術(shù)來(lái)優(yōu)化性能――即將后臺(tái)訪問(wèn)過(guò)來(lái)的單條請(qǐng)求 (Get) 在內(nèi)存層聚合成一次批量請(qǐng)求 (Batch Get)。

路由收斂

因?yàn)槊總€(gè)數(shù)據(jù)都是根據(jù)鍵值單獨(dú)進(jìn)行路由的,如果要進(jìn)行請(qǐng)求合并,我們就必須確保同一個(gè)批量請(qǐng)求內(nèi)的數(shù)據(jù),都會(huì)尋址到相同的 Paxos Group 上。因此,我們必須在內(nèi)存層將落到同一臺(tái)存儲(chǔ)機(jī)器上的 Get 請(qǐng)求聚合起來(lái)。我們首先在內(nèi)存層和存儲(chǔ)層采用了相同的路由算法,然后將內(nèi)存層的組數(shù)同存儲(chǔ)層的組數(shù)進(jìn)行對(duì)齊,來(lái)完成了這一目標(biāo)。

怎樣實(shí)踐微信后臺(tái)的海量數(shù)據(jù)冷熱分級(jí)架構(gòu)設(shè)計(jì)

相關(guān)工作

在設(shè)計(jì)的階段,我們充分的調(diào)研了業(yè)界的各類(lèi)方案,大到系統(tǒng)的整體架構(gòu),小到具體的技術(shù)點(diǎn)。各種方案自有應(yīng)用場(chǎng)景、各有千秋,不能單純以好壞區(qū)別,我們同樣基于自己的業(yè)務(wù)場(chǎng)景,謹(jǐn)慎的選擇合適的方案,或者棄而不用。在此盡量敘述。

處理 SNS 類(lèi)業(yè)務(wù)生成的數(shù)據(jù),業(yè)界有多種的冷熱分離架構(gòu)可以參考。我們以 Facebook 的 Cold Storage 系統(tǒng)舉例而言,它也是基于冷熱分層的想法,設(shè)計(jì)出了服務(wù)它們照片業(yè)務(wù)數(shù)據(jù)的存儲(chǔ)方案。不同的是它采用了軟硬件結(jié)合的方法,一方面定制專(zhuān)門(mén)的服務(wù)器(包括硬盤(pán)、電源等)和數(shù)據(jù)中心,一方面降低冷數(shù)據(jù)的備份數(shù)、增加糾刪碼等手段。

然而它們的經(jīng)驗(yàn)我們是無(wú)法徹底套用的,主要兩種原因:我們可使用的機(jī)器機(jī)型是固定的,不存在自己定制硬件的條件。同時(shí)它處理的是照片這種大 value 的數(shù)據(jù)。而我們基本上是文本這種類(lèi)型的小 value 數(shù)據(jù)。從前文提及的 TB 訪問(wèn)量角度來(lái)看,它們處理的數(shù)據(jù)是容量瓶頸的,而我們處理的是 IO 瓶頸的,可以算是不太冷的冷數(shù)據(jù)帶來(lái)的挑戰(zhàn)。所以,我們只能實(shí)現(xiàn)自己的冷數(shù)據(jù)管理策略。

同樣,業(yè)界有諸多關(guān)于如何實(shí)現(xiàn)數(shù)據(jù)一致性的方案。包括我們微信自研的 Quorum 協(xié)議,它是一種 NWR 協(xié)議,采用異步同步的方式實(shí)現(xiàn)數(shù)據(jù)多副本。即然是異步同步,那在多副本達(dá)到最終一致,必然存在一個(gè)時(shí)間差,那么在單機(jī)出現(xiàn)離線的情況下,就會(huì)有一定概率導(dǎo)致數(shù)據(jù)的不可用。而我們追求的是在單點(diǎn)故障下,所有的數(shù)據(jù)都保證強(qiáng)可用性。

因此,我們采用了無(wú)主的去中心化的 Paxos Group 實(shí)現(xiàn)了這一目標(biāo),其中非租約是 PaxosStore 架構(gòu)的一個(gè)創(chuàng)新亮點(diǎn)。在故障時(shí)通常系統(tǒng)是抖動(dòng)的,會(huì)有時(shí)斷時(shí)續(xù)的狀況,常見(jiàn)的租約做法在這種場(chǎng)景下容易出現(xiàn)反復(fù)切換主機(jī)而導(dǎo)致長(zhǎng)期不可用,而 PaxosStore 的非租約結(jié)構(gòu)能夠輕松應(yīng)對(duì),始終提供良好的服務(wù)。PaxosStore 核心代碼正在整理開(kāi)源當(dāng)中,預(yù)計(jì)四季度會(huì)正式發(fā)布,同時(shí)該項(xiàng)目的底層框架也基于我們已開(kāi)源的協(xié)程庫(kù) github.com/libco。

看完上述內(nèi)容,你們對(duì)怎樣實(shí)踐微信后臺(tái)的海量數(shù)據(jù)冷熱分級(jí)架構(gòu)設(shè)計(jì)有進(jìn)一步的了解嗎?如果還想了解更多知識(shí)或者相關(guān)內(nèi)容,請(qǐng)關(guān)注億速云行業(yè)資訊頻道,感謝大家的支持。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI