聊聊分布式數(shù)據(jù)庫的 Sharding,你了解嗎?
最近我們團(tuán)隊(duì)的D-SMART在做螞蟻的OCEANBASE的適配,因此又把OB的資料拿出來,重新做研究。要想讓D-SMART納管OCEANBASE,不像一些傳統(tǒng)的監(jiān)控軟件那么簡單,只要把一些關(guān)鍵指標(biāo)接入進(jìn)來,搞幾個(gè)基線模板就可以做做簡單的報(bào)警了。必須對OB的基本原理、配置信息、運(yùn)維要點(diǎn)、常見故障、巡檢要點(diǎn)等做大量的歸納總結(jié),并找到一些實(shí)際的用戶,進(jìn)行大量的測試,才能完成初步的適配,隨后不斷積累運(yùn)維經(jīng)驗(yàn),才能讓這個(gè)工具的能力越來越強(qiáng)。這也是做數(shù)據(jù)庫的智能運(yùn)維工具的不易之處。要重新學(xué)習(xí)OB,所以近期我會(huì)和大家分享一些我學(xué)習(xí)OB的心得。
研究OB數(shù)據(jù)庫,我們首先需要從這張OB架構(gòu)圖上開始分析。上面這張三個(gè)ZONE的OB架構(gòu)圖來自于OB的官方手冊。從這張圖上來看,OB除了總控服務(wù)(Root Service)是主備模式,采用一主N備的模式,其他的組件都可以看成是分布式去中心化的。其SQL引擎、事務(wù)引擎、存儲(chǔ)引擎是采用分區(qū)分片的方式的。每個(gè)OBSERVER都包含一個(gè)SQL引擎,一個(gè)事務(wù)引擎、一個(gè)存儲(chǔ)引擎和一組數(shù)據(jù)分區(qū)。
這種SHARDING架構(gòu)的數(shù)據(jù)庫系統(tǒng)十分適合高并發(fā)的小型交易,其中最為典型的就是支付寶業(yè)務(wù)。因?yàn)榭梢愿鶕?jù)用戶的ID,將大并發(fā)量的用戶通過算法分散到各個(gè)對等的OBSERVER上去,通過擴(kuò)展OBSERVER的數(shù)量就可以橫向擴(kuò)展OB的并發(fā)處理能力。
OB的ZONE具備遠(yuǎn)程部署能力,因此OB原生態(tài)具有支持同城雙活的能力,可以將不同的ZONE部署在不同的數(shù)據(jù)中心里。OB的數(shù)據(jù)是采用多副本的,在每個(gè)ZONE里存儲(chǔ)一份,并通過PAXOS分布式選舉算法選舉LEADER。OB的數(shù)據(jù)副本粒度可以到分區(qū)級。
SHARE NOTHING架構(gòu)的分布式數(shù)據(jù)庫一般被稱為MPP數(shù)據(jù)庫,集群上不共享任何數(shù)據(jù),因此這種架構(gòu)很容易橫向擴(kuò)展。作為MPP分布式數(shù)據(jù)庫的設(shè)計(jì)理念,主要在高可用(采用多副本存儲(chǔ)數(shù)據(jù),單點(diǎn)故障不影響數(shù)據(jù)庫)、可橫向擴(kuò)展(因?yàn)椴捎肧HARE NOTHING,因此不存在緩沖區(qū)融合的問題,增加節(jié)點(diǎn)就可以增加處理能力)、使用簡單(自動(dòng)分庫分表、自動(dòng)數(shù)據(jù)路由,研發(fā)人員比較容易掌握)、運(yùn)維方便等。
高可用這條毋庸置疑,比如OB這種架構(gòu),一份數(shù)據(jù)會(huì)在多個(gè)ZONE里有多個(gè)副本存儲(chǔ),甚至有的ZONE還可以位于遠(yuǎn)程或者異地,可用性方面是絕對沒有問題的。不過OB這種靠一套數(shù)據(jù)庫實(shí)現(xiàn)同城雙活的方案,對于一般的系統(tǒng)來說可能夠用了,不過對于一些可靠性要求十分高的系統(tǒng)來說,也是不夠的。雖然ZONE可以跨數(shù)據(jù)中心,但是數(shù)據(jù)庫本身也是一個(gè)單點(diǎn),一旦整個(gè)數(shù)據(jù)庫出問題了,那么業(yè)務(wù)也就中斷了。使用可跨數(shù)據(jù)中心的分布式數(shù)據(jù)庫之后,還需要不需要再搞高可用,還是只依賴于單一數(shù)據(jù)庫的高可用,這一點(diǎn)就仁者見仁智者見智了。
可橫向擴(kuò)展也是沒問題的,現(xiàn)在的網(wǎng)絡(luò)能力下,SHARE NOTHING集群可以很方便的擴(kuò)展到數(shù)十個(gè)甚至數(shù)百個(gè)??梢詷?gòu)建十分龐大的數(shù)據(jù)庫集群。這是MPP數(shù)據(jù)庫的優(yōu)勢所在。不過對于大多數(shù)傳統(tǒng)架構(gòu)的業(yè)務(wù)系統(tǒng)來說,大集群的MPP所提供的處理能力不一定是必須的,有可能一臺(tái)2路服務(wù)器就已經(jīng)遠(yuǎn)遠(yuǎn)超出你的業(yè)務(wù)處理能力的需求了,這時(shí)候選擇MPP數(shù)據(jù)庫的目的應(yīng)該就不是橫向擴(kuò)展了。在我遇到的很多用戶的應(yīng)用場景中,選擇具有橫向擴(kuò)展能力的架構(gòu)實(shí)際上是一個(gè)偽命題。
運(yùn)維方便這一點(diǎn)目前來看要從兩個(gè)方面來看,對于日常運(yùn)維來說,如果不出一些特別的問題,那么MPP分布式數(shù)據(jù)庫總體來說運(yùn)維還是比較簡單的,日常運(yùn)維主要看看SQL優(yōu)化就可以了,因?yàn)楦呖捎眉軜?gòu)屏蔽了大量的硬件單點(diǎn)故障帶來的系統(tǒng)問題,因此日常運(yùn)維的壓力是會(huì)得到緩解的。如果出現(xiàn)一些大一點(diǎn)的問題,那么運(yùn)維人員也是無能為力的,MPP數(shù)據(jù)庫的復(fù)雜性決定了,一旦出問題,很可能數(shù)據(jù)庫原廠都不一定能很快搞定,因此故障處理的主力就是原廠了。從這一點(diǎn)上來講,使用MPP數(shù)據(jù)庫,運(yùn)維人員的壓力會(huì)比較小。
使用簡單這一點(diǎn),是MPP數(shù)據(jù)庫最令客戶喜歡的一點(diǎn),不過這一點(diǎn)上往往爭議也最大。實(shí)際上分布式數(shù)據(jù)庫的最早雛形是互聯(lián)網(wǎng)企業(yè)的分庫分表,這方面在世紀(jì)之初我們在給運(yùn)營商做優(yōu)化的時(shí)候也大量的使用。把一個(gè)數(shù)據(jù)庫按照業(yè)務(wù)分拆成多個(gè),無法分拆的庫做復(fù)制,進(jìn)行讀寫分離處理,從而讓已經(jīng)達(dá)到縱向擴(kuò)展極限的系統(tǒng)能夠分拆負(fù)載,這個(gè)方法被稱為分庫。
對于開發(fā)人員來說,分庫還是比較容易實(shí)現(xiàn)的,只要開發(fā)廠家的水平不是太差,分庫后的聚合計(jì)算方面的研發(fā)能力稍微好一點(diǎn),分庫還是比較容易實(shí)現(xiàn)的,因?yàn)榉謳焓前凑諛I(yè)務(wù)去分的,大部分的計(jì)算都會(huì)集中在庫里,只有少量的計(jì)算才需要跨庫的聚合計(jì)算。不過我也遇到過很極端的情況,一個(gè)數(shù)據(jù)庫被分為6個(gè)小庫后,開發(fā)人員不愿意自己程序里實(shí)現(xiàn)聚合計(jì)算,只能創(chuàng)建OGG復(fù)制鏈路,把部分分出去的數(shù)據(jù)再復(fù)制回來。這套系統(tǒng)上線不到半年,這種OGG復(fù)制鏈路已經(jīng)有好幾十條了。對于MPP數(shù)據(jù)庫來說,分庫就更為簡單了,SQL引擎可以自動(dòng)實(shí)現(xiàn)跨庫的表連接,開發(fā)人員也就不需要再去復(fù)制表數(shù)據(jù)了。
MPP架構(gòu)應(yīng)用的另外一種模式是分表,當(dāng)分庫已經(jīng)不能滿足要求的時(shí)候,就需要分表了??赡艽蠹覄傞_始的時(shí)候覺得分表不就是比分庫分的更細(xì)一點(diǎn)嗎,既然分庫沒問題,那么分表也不應(yīng)有有問題了。
實(shí)際上并不是這樣的,分表有兩種形式,一種是把一個(gè)庫里的多張表分不到不同的OBSERVER中去,一種是把一張表分為多個(gè)片,存儲(chǔ)到不同的OBSERVER中去。第一種分表對于應(yīng)用開發(fā)來說還比較好辦,MPP數(shù)據(jù)庫的SQL引擎會(huì)做聚合計(jì)算,因此對于開發(fā)來說并沒有什么不同。有差異的是性能,跨多個(gè)OBSERVER的聚合查詢的性能和單機(jī)數(shù)據(jù)庫比,在很多方面都是存在差異的,這和分布式數(shù)據(jù)庫的優(yōu)化器和執(zhí)行器的水平有很大的關(guān)系。跨庫數(shù)據(jù)的聚合計(jì)算肯定會(huì)比單機(jī)有更多的延時(shí),這些延時(shí)主要是在網(wǎng)絡(luò)上的。不過這些都不是最主要的因素,最主要的是算子下推的操作。分布式數(shù)據(jù)庫的算子下推可以利用并行執(zhí)行的優(yōu)勢來加速,不過算子下推的粒度和能力,在不同的數(shù)據(jù)庫廠商實(shí)現(xiàn)方面存在技術(shù)差距,這一點(diǎn)往往需要經(jīng)過嚴(yán)格的對比才能看得出來。
分片是一個(gè)更復(fù)雜的問題,我們要把一張表分成多個(gè)片段分布到多個(gè)OBSERVER中去,那么我們必須要按照某個(gè)SHARDING KEY來分表。如果分表后,我們對這張表的查詢語句上都帶有這個(gè)SHARDING KEY的過濾條件,那么優(yōu)化器在分解執(zhí)行算子的時(shí)候,可以很方便的進(jìn)行分區(qū)裁剪,從而降低執(zhí)行成本。如果我們的SQL中不帶SHARDING KEY過濾條件,那么這條SQL就會(huì)分布到所有的這張表所在的OBSERVER上去執(zhí)行,這樣可能會(huì)放大SQL執(zhí)行的資源消耗,也會(huì)影響SQL的執(zhí)行效率。
分庫分表另外一個(gè)對性能影響較大的因素是多表關(guān)聯(lián)查詢方面的性能問題。比如某個(gè)表的某個(gè)分片在OBS1上,而關(guān)聯(lián)表的分區(qū)在OBS2上,那么這個(gè)分布式關(guān)聯(lián)操作的性能就不如二者都存放在OBS1上了。OB數(shù)據(jù)庫引入了一個(gè)表組(table group)的邏輯結(jié)構(gòu)。設(shè)置為同一個(gè)table group的多張表具有相同或者像類似的分區(qū)策略,其關(guān)聯(lián)操作也比較多,這樣可以確保這類業(yè)務(wù)的性能不會(huì)有太大的下降。
實(shí)際上我們還經(jīng)常遇到一個(gè)問題就是一張分區(qū)的大表經(jīng)常需要和一些小表進(jìn)行關(guān)聯(lián),有些數(shù)據(jù)庫也支持將一些小表復(fù)制到多個(gè)數(shù)據(jù)庫分片中,從而提高這些關(guān)聯(lián)操作的性能。
在很多分布式數(shù)據(jù)庫的設(shè)計(jì)之初,數(shù)據(jù)庫研發(fā)人員是希望分布式數(shù)據(jù)庫能夠很方便的讓人使用,而實(shí)際上分布式數(shù)據(jù)庫和集中式數(shù)據(jù)庫在架構(gòu)上的不同決定了,用好分布式數(shù)據(jù)庫肯定需要有更高水平的設(shè)計(jì),利用分布式數(shù)據(jù)庫的特性,做精心的設(shè)計(jì),盡可能避免分布式數(shù)據(jù)庫中的那些坑,才能把應(yīng)用做的更好。如果我們的數(shù)據(jù)庫廠商總是避開這些不談,等用戶在他們的數(shù)據(jù)庫上開發(fā)出了不那么令人滿意的系統(tǒng)來,那時(shí)候再去說用戶不會(huì)用分布式數(shù)據(jù)庫,那就不夠地道了。