DDIA笔记—第六章 数据分区
第六章 數(shù)據(jù)分區(qū)
數(shù)據(jù)分區(qū)與數(shù)據(jù)復(fù)制
分區(qū)通常與復(fù)制結(jié)合使用,即每個(gè)分區(qū)在多個(gè)節(jié)點(diǎn)都存在副本,這就意味著某條記錄屬于特定的分區(qū),而同樣的內(nèi)容會(huì)保存在不同的節(jié)點(diǎn)上以提高系統(tǒng)的容錯(cuò)性。
每個(gè)節(jié)點(diǎn)同時(shí)充當(dāng)某些分區(qū)的主副本和其他分區(qū)的從副本:
如何進(jìn)行分區(qū)?
如何決定哪些記錄放在哪些節(jié)點(diǎn)上?分區(qū)的主要目的是將數(shù)據(jù)和查詢負(fù)載均勻的分布在所有節(jié)點(diǎn)上。如果分區(qū)不均勻,則會(huì)出現(xiàn)某些分區(qū)節(jié)點(diǎn)比其他分區(qū)承擔(dān)更多的數(shù)據(jù)量和查詢負(fù)載,稱之為傾斜。更為嚴(yán)重的情況是,所有的負(fù)載都集中在一個(gè)分區(qū)節(jié)點(diǎn)上,這種負(fù)載嚴(yán)重不成比例的分區(qū)稱為系統(tǒng)熱點(diǎn)。避免系統(tǒng)熱點(diǎn)最簡(jiǎn)單的方式就是將記錄隨機(jī)分配給所有節(jié)點(diǎn),但這有帶來了另一個(gè)問題:如何讀取數(shù)據(jù)?(簡(jiǎn)單的鍵-值數(shù)據(jù)模型,可以通過關(guān)鍵字來訪問記錄)
鍵-值數(shù)據(jù)的分區(qū)
基于關(guān)鍵字區(qū)間分區(qū)
為每個(gè)分區(qū)分配一段連續(xù)的關(guān)鍵字或者關(guān)鍵值區(qū)間范圍。為了更均勻的分布數(shù)據(jù),分區(qū)邊界理應(yīng)適配數(shù)據(jù)本身的分布特征。
但是基于關(guān)鍵字的區(qū)間分區(qū)的缺點(diǎn)是某些訪問模式可能會(huì)導(dǎo)致熱點(diǎn),例如:采用時(shí)間戳作為關(guān)鍵字,則分區(qū)對(duì)應(yīng)于一個(gè)時(shí)間范圍,如果將每天作為一個(gè)分區(qū),同一天內(nèi)所有寫入都集中在同一個(gè)分區(qū),而其他的分區(qū)始終處于空閑狀態(tài)。
基于關(guān)鍵字哈希值分區(qū)
一個(gè)好的哈希函數(shù)可以處理數(shù)據(jù)傾斜并使其均勻分布。一旦找到了合適的關(guān)鍵字哈希函數(shù),就可以為每個(gè)分區(qū)分配一個(gè)哈希范圍,關(guān)鍵字根據(jù)其哈希值的范圍劃分到不同的分區(qū)中。
這種方式看似非常完美,但是在做范圍查詢時(shí),往往會(huì)變的非常麻煩:即使關(guān)鍵字相鄰,但經(jīng)過哈希函數(shù)之后可能會(huì)被分散到不同的分區(qū)中。在MongoDB中,如果啟用了基于哈希的分片模式,則區(qū)間查詢會(huì)發(fā)送到所有分區(qū)上。
綜上,基于哈希的分區(qū)方法可以減輕熱點(diǎn),但無(wú)法做到完全避免。
分區(qū)與二級(jí)索引
二級(jí)索引帶來的主要挑戰(zhàn)是它們不能規(guī)整的映射到分區(qū)中。有兩種主要的方法來支持對(duì)二級(jí)索引進(jìn)行分區(qū):
基于文檔分區(qū)的二級(jí)索引
如圖,每條記錄都有唯一的ID,首先用此ID對(duì)數(shù)據(jù)庫(kù)進(jìn)行分區(qū)(例如:0 <= ID < 500屬于分區(qū)0,500 <= ID < 1000屬于分區(qū)1)。現(xiàn)在用戶需要搜索汽車,可以支持按汽車顏色和廠商進(jìn)行過濾,所以需要在顏色和制造商上設(shè)定二級(jí)索引。聲明這些索引之后,數(shù)據(jù)庫(kù)會(huì)自動(dòng)創(chuàng)建索引。
在這種索引方法中,每個(gè)分區(qū)完全獨(dú)立,各自維護(hù)自己的二級(jí)索引,因此文檔分區(qū)索引也被稱為本地索引。
讀取時(shí)需要注意:如果是要查詢所有紅色汽車(假設(shè)沒有對(duì)ID做特殊處理),則查詢請(qǐng)求需要發(fā)送到所有的分區(qū),然后再合并結(jié)果。所以導(dǎo)致了查詢代價(jià)高昂、讀延遲加大。
基于詞條的二級(jí)索引分區(qū)
另一種方法,我們可以對(duì)所有的數(shù)據(jù)構(gòu)建全局索引,同時(shí),為了避免瓶頸,不能將全局索引存儲(chǔ)在一個(gè)節(jié)點(diǎn)上,否則就破壞了設(shè)計(jì)分區(qū)均衡的目標(biāo)。所以,全局索引也必須分區(qū),且可以與數(shù)據(jù)關(guān)鍵字采用不同的分區(qū)策略。
如圖,所有顏色為紅色的汽車的ID收錄在索引color:red中,而索引本身也是分區(qū)的,例如從a~r開始的顏色索引放在分區(qū)0中。我們將這種索引方案稱為詞條分區(qū)。和前面討論的方法一樣,可以直接通過關(guān)鍵字來全局劃分索引,或者對(duì)其取哈希值,各自的優(yōu)點(diǎn)在前面也都提到了。
這種全局的詞條索引相比于文檔分區(qū)索引的主要優(yōu)點(diǎn)是:它的讀取更為高效,即不需要向所有分區(qū)都查詢一遍。但是缺點(diǎn)也非常明顯:由于需要維護(hù)索引,導(dǎo)致它的寫入速度非常慢。理想情況下,索引應(yīng)該時(shí)刻保持最新,但是,對(duì)于詞條分區(qū)來說,這需要一個(gè)跨多個(gè)相關(guān)分區(qū)的分布式事務(wù)支持(這也是現(xiàn)有數(shù)據(jù)庫(kù)不支持同步更新二級(jí)索引的原因)。
分區(qū)再平衡
隨著時(shí)間的推移,數(shù)據(jù)庫(kù)可能總會(huì)出現(xiàn),某些變化:
- 查詢壓力增加,因此需要更多的CPU來處理負(fù)載;
- 數(shù)據(jù)規(guī)模增加,因此需要更多的磁盤和內(nèi)存來存儲(chǔ)數(shù)據(jù);
- 節(jié)點(diǎn)可能出現(xiàn)故障,因此需要其他節(jié)點(diǎn)代替失效節(jié)點(diǎn);
所有這些變化都要求數(shù)據(jù)和請(qǐng)求能從一個(gè)節(jié)點(diǎn)轉(zhuǎn)移到另一個(gè)節(jié)點(diǎn),這樣一個(gè)過程就稱為再平衡(動(dòng)態(tài)平衡)。無(wú)論對(duì)于哪種分區(qū)方案,分區(qū)再平衡通常只少要滿足:
- 平衡之后,負(fù)載、數(shù)據(jù)存儲(chǔ)、讀寫請(qǐng)求等應(yīng)該在集群范圍更均勻的分布;
- 再平衡執(zhí)行過程中,數(shù)據(jù)庫(kù)應(yīng)該可以繼續(xù)正常提供讀寫服務(wù);
- 避免不必要的負(fù)載遷移,并盡量減少網(wǎng)絡(luò)和磁盤I/O影響;
動(dòng)態(tài)再平衡策略
為什么不采用模運(yùn)算?
如果節(jié)點(diǎn)數(shù)發(fā)生變化,將會(huì)導(dǎo)致大量的關(guān)鍵字需要從現(xiàn)有節(jié)點(diǎn)遷移到另一個(gè)節(jié)點(diǎn),頻繁的遷移大大增加再平衡的成本。
固定數(shù)量的分區(qū)
如圖,如果集群中添加了一個(gè)新節(jié)點(diǎn),該新節(jié)點(diǎn)可以從每個(gè)現(xiàn)有的節(jié)點(diǎn)上勻走幾個(gè)分區(qū),直到分區(qū)再次達(dá)到全局平衡(當(dāng)然,如果增加的節(jié)點(diǎn)性能更加強(qiáng)大,則可以給它分配更過的分區(qū),從而分擔(dān)更多的負(fù)載)。刪除的話,就是一個(gè)逆向的操作。這種方式不會(huì)改變關(guān)鍵字到分區(qū)的映射關(guān)系,唯一要調(diào)整的是分區(qū)與節(jié)點(diǎn)的對(duì)應(yīng)關(guān)系。
在這種方式中,為了使得相關(guān)操作變得非常簡(jiǎn)單,分區(qū)的數(shù)量往往中數(shù)據(jù)庫(kù)創(chuàng)建時(shí)就已經(jīng)確定好(原則上可以拆分和合并,但是為了簡(jiǎn)單,許多數(shù)據(jù)庫(kù)決定不支持分區(qū)拆分和合并),所以,在初始化時(shí),就會(huì)設(shè)置一個(gè)足夠大的分區(qū)數(shù)(每個(gè)分區(qū)都會(huì)有額外的管理開銷)。如果數(shù)據(jù)集的規(guī)模不確定,此時(shí)如何選擇合適的分區(qū)數(shù)以及分區(qū)大小就會(huì)有些困難。
動(dòng)態(tài)分區(qū)
簡(jiǎn)單的理解就是,當(dāng)分區(qū)的數(shù)據(jù)增長(zhǎng)超過一個(gè)參數(shù)閾值(HBase默認(rèn)值為10GB)時(shí),它就拆分為兩個(gè)分區(qū)(可以將其中一部分轉(zhuǎn)移到其他節(jié)點(diǎn)),每個(gè)分區(qū)承擔(dān)一半的數(shù)據(jù)量。相反,如果數(shù)據(jù)被大量刪除,并且縮小到某個(gè)閾值以下,則將其與相鄰分區(qū)進(jìn)行合并。
動(dòng)態(tài)分區(qū)的一個(gè)優(yōu)點(diǎn)是:分區(qū)數(shù)量可以自動(dòng)適配數(shù)據(jù)總量。
但對(duì)于一個(gè)空的數(shù)據(jù)庫(kù),初始時(shí)可能會(huì)從一個(gè)分區(qū)開始,這樣在達(dá)到第一個(gè)分裂點(diǎn)之前,所有寫入請(qǐng)求都由單個(gè)節(jié)點(diǎn)來處理,而其他節(jié)點(diǎn)處于空閑狀態(tài)。為了緩解這種問題,HBase和MongoDB允許采用預(yù)分裂(配置一組初始分區(qū)),同時(shí),預(yù)分裂要求知道一些關(guān)鍵字的分布情況。
按節(jié)點(diǎn)比例分區(qū)
動(dòng)態(tài)分區(qū)中分區(qū)的數(shù)量與數(shù)據(jù)集的大小成正比,固定數(shù)量分區(qū)中分區(qū)大小也與數(shù)據(jù)集反大小成正比,這兩種方式都與節(jié)點(diǎn)數(shù)無(wú)關(guān)。
一些數(shù)據(jù)庫(kù)系統(tǒng)(Cassandra、Ketama)采用了第三種方式,使分區(qū)數(shù)與集群節(jié)點(diǎn)數(shù)成正比。也就是說,每個(gè)節(jié)點(diǎn)具有固定數(shù)量的分區(qū)。當(dāng)一個(gè)新節(jié)點(diǎn)加入集群時(shí),它隨機(jī)選擇固定數(shù)量的現(xiàn)有分區(qū)進(jìn)行分裂,然后拿走這些分區(qū)的一半數(shù)據(jù)。
自動(dòng)與手動(dòng)再平衡操作
再平衡總體上講是一個(gè)昂貴的操作,它需要重新路由請(qǐng)求,并將大量數(shù)據(jù)從一個(gè)節(jié)點(diǎn)遷移到另一個(gè)節(jié)點(diǎn)。
全自動(dòng)再平衡雖然方便,但有可能在再平衡過程中出現(xiàn)難以預(yù)測(cè)的情況。例如:假設(shè)某個(gè)節(jié)點(diǎn)負(fù)載過重,對(duì)請(qǐng)求對(duì)響應(yīng)暫時(shí)受到影響,其他的節(jié)點(diǎn)可能會(huì)得到結(jié)論:該節(jié)點(diǎn)失效;接著觸發(fā)自動(dòng)平衡來轉(zhuǎn)移負(fù)載,這無(wú)疑會(huì)加重該節(jié)點(diǎn)、其他節(jié)點(diǎn)以及網(wǎng)絡(luò)的負(fù)載。
所以,你怎么選擇,自動(dòng) or 手動(dòng)?
請(qǐng)求路由
客戶端如何知道要連接哪個(gè)節(jié)點(diǎn)?
這個(gè)問題有以下幾種處理策略:
- 允許客戶端鏈接任意節(jié)點(diǎn)。如果某節(jié)點(diǎn)恰好擁有所請(qǐng)求的分區(qū),則直接處理該請(qǐng)求;否則,將請(qǐng)求轉(zhuǎn)發(fā)給下一個(gè)節(jié)點(diǎn),接收答復(fù),并將答復(fù)返回給客戶端;
- 所有客戶端的請(qǐng)求發(fā)給路由層,由路由層將請(qǐng)求轉(zhuǎn)發(fā)給對(duì)應(yīng)的分區(qū)節(jié)點(diǎn);
- 客戶端自己感知分區(qū)和節(jié)點(diǎn)的分配關(guān)系;
所以,這里的核心問題就變成了:作出路由決策的組件(某個(gè)節(jié)點(diǎn)、路由層、客戶端)是如何知道分區(qū)與節(jié)點(diǎn)的對(duì)應(yīng)關(guān)系以及變化情況的呢?很多分布式數(shù)據(jù)系統(tǒng)依靠獨(dú)立的協(xié)調(diào)服務(wù)(如ZooKeeper)跟蹤集群范圍內(nèi)的元數(shù)據(jù)。類似的還有:MongoDB依賴于自己的配置服務(wù)器和mongos守護(hù)進(jìn)程來充當(dāng)路由層等。
每個(gè)節(jié)點(diǎn)都向Zookeeper中注冊(cè)自己,ZooKeeper維護(hù)了分區(qū)到節(jié)點(diǎn)的最終映射關(guān)系。其他參與者可以向ZooKeeper訂閱此信息。一旦分區(qū)發(fā)生了改變,或者刪除、添加節(jié)點(diǎn),ZooKeeper都會(huì)通知參與者。
并行查詢執(zhí)行
大規(guī)模并行計(jì)算(massively parallel processing,MPP)中查詢類型方面要復(fù)雜的多,典型的操作會(huì)包含多個(gè)聯(lián)合、過濾、分組、聚合等操作。MPP查詢優(yōu)化器會(huì)將復(fù)雜的查詢分解成許多執(zhí)行階段和分區(qū),以便在不同節(jié)點(diǎn)上并行執(zhí)行。
總結(jié)
以上是生活随笔為你收集整理的DDIA笔记—第六章 数据分区的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何在电脑版快投屏中使用USB有线投屏功
- 下一篇: Go 排序方式