分布式數(shù)據(jù)庫(kù)拆分的常用辦法是什么

今天就跟大家聊聊有關(guān)分布式數(shù)據(jù)庫(kù)拆分的常用辦法是什么,可能很多人都不太了解,為了讓大家更加了解,小編給大家總結(jié)了以下內(nèi)容,希望大家根據(jù)這篇文章可以有所收獲。

站在用戶(hù)的角度思考問(wèn)題,與客戶(hù)深入溝通,找到貞豐網(wǎng)站設(shè)計(jì)與貞豐網(wǎng)站推廣的解決方案,憑借多年的經(jīng)驗(yàn),讓設(shè)計(jì)與互聯(lián)網(wǎng)技術(shù)結(jié)合,創(chuàng)造個(gè)性化、用戶(hù)體驗(yàn)好的作品,建站類(lèi)型包括:成都網(wǎng)站設(shè)計(jì)、成都網(wǎng)站建設(shè)、企業(yè)官網(wǎng)、英文網(wǎng)站、手機(jī)端網(wǎng)站、網(wǎng)站推廣、空間域名、虛擬空間、企業(yè)郵箱。業(yè)務(wù)覆蓋貞豐地區(qū)。

分布式系統(tǒng)做「伸縮性」最重要的就是先做好「無(wú)狀態(tài)」,如此才可以隨心所欲的進(jìn)行橫向“擴(kuò)展”,而不用擔(dān)心在多個(gè)副本之間切換會(huì)產(chǎn)生錯(cuò)亂。

不過(guò),就算做好了橫向擴(kuò)展,本質(zhì)上還是一個(gè)“大程序”,只是變得「可復(fù)制」了而已。

如果要消滅“大程序”,那就得“切分”,做好切分必然離不開(kāi)「高內(nèi)聚低耦合」的核心思想?!斗植际较到y(tǒng)關(guān)注點(diǎn)——「高內(nèi)聚低耦合」詳解》這篇聊的就是這個(gè)。

“擴(kuò)”的話先考慮「垂直擴(kuò)」(加硬件,錢(qián)能解決的都不是問(wèn)題),再考慮「水平擴(kuò)」(無(wú)狀態(tài)改造+多節(jié)點(diǎn)部署,這是小手術(shù))。

“切”的話一般就是「垂直切」(根據(jù)業(yè)務(wù)切分,這是大手術(shù)),偶爾會(huì)用到「水平切」(其實(shí)就是單個(gè)應(yīng)用里的分層,比如前后端分離)。

以上這些呢都是應(yīng)用程序?qū)用娴墓ぷ?。一般情況下,在應(yīng)用程序?qū)用孀鲎鍪中g(shù),再配合以緩存的充分運(yùn)用,就可以支撐系統(tǒng)發(fā)展很長(zhǎng)時(shí)間了。特別是數(shù)據(jù)量不大,只是請(qǐng)求量大的「CPU密集型」場(chǎng)景。

但是,如果所處的工作場(chǎng)景是一個(gè)非常成熟且具有一定規(guī)模的項(xiàng)目,越發(fā)展到后面瓶頸總是出現(xiàn)在數(shù)據(jù)庫(kù)這里。甚至?xí)霈F(xiàn)cpu長(zhǎng)期高負(fù)荷、宕機(jī)等現(xiàn)象。

在如此場(chǎng)景下,就不得不對(duì)數(shù)據(jù)庫(kù)開(kāi)刀了。這次就來(lái)和你聊聊做數(shù)據(jù)庫(kù)的「伸縮性」有哪些好方法。

核心訴求

面臨數(shù)據(jù)庫(kù)需要開(kāi)刀的時(shí)候,整個(gè)系統(tǒng)往往已經(jīng)長(zhǎng)成這個(gè)樣子了。

分布式數(shù)據(jù)庫(kù)拆分的常用辦法是什么

正如前面所說(shuō),這時(shí)候的瓶頸往往會(huì)體現(xiàn)在「CPU」上。

因?yàn)閷?duì)數(shù)據(jù)庫(kù)來(lái)說(shuō),硬盤(pán)和內(nèi)存的擴(kuò)容相對(duì)容易,因?yàn)樗鼈兌伎梢灾苯佑谩霸黾印钡姆绞竭M(jìn)行。

CPU就不同了,一旦CPU飆高,最多檢查下索引有沒(méi)有做好,完了之后基本就只能干看著。

所以解決這個(gè)問(wèn)題的思路自然就變成了:如何將一個(gè)數(shù)據(jù)庫(kù)的CPU壓力分?jǐn)偟蕉鄠€(gè)CPU上去。甚至可以做到按需隨時(shí)增加。

那這不就是和應(yīng)用程序一樣做「切分」嘛。也是分布式系統(tǒng)的「分治」思想體現(xiàn)。

既然是切分,本質(zhì)上就和應(yīng)用程序一樣,也分為「垂直切分」和「水平切分」。

垂直切分

垂直切分有時(shí)候也會(huì)被稱(chēng)作「縱向切分」。

同應(yīng)用程序一樣,它是以「業(yè)務(wù)」為維度的切分方式,在不同的數(shù)據(jù)庫(kù)服務(wù)器上跑不同業(yè)務(wù)的數(shù)據(jù)庫(kù),各司其職。

一般情況下,Z哥建議你優(yōu)先考慮「垂直切分」而不是「水平切分」,為什么呢?你可以隨意打開(kāi)手頭項(xiàng)目中的SQL語(yǔ)句看看,我想必然存在著大量的「join」和「transaction」關(guān)鍵字,這種關(guān)聯(lián)查詢(xún)和事務(wù)操作,本質(zhì)上是一種「關(guān)系綁定」,一旦面臨數(shù)據(jù)庫(kù)拆分之后,就沒(méi)法玩了

此時(shí)你只有2個(gè)選擇。

  1. 要么將不必要的「關(guān)系***」邏輯舍棄掉,這需要在業(yè)務(wù)上作出調(diào)整,去除不必要的“批量操作”業(yè)務(wù),或者去除不必要的強(qiáng)一致性事務(wù)。不過(guò)你也知道,肯定有一些場(chǎng)景是去不完的。

  2. 要么將「合并」,「關(guān)聯(lián)」等邏輯上浮,體現(xiàn)到業(yè)務(wù)邏輯層甚至是應(yīng)用層的代碼中。

最終,不管怎么選擇,改動(dòng)起來(lái)都是一個(gè)大工程。

為了讓這個(gè)工程盡可能的動(dòng)作小一些,追求更好的性?xún)r(jià)比,需要堅(jiān)持一個(gè)原則——“避免拆分緊密關(guān)聯(lián)的表”。

因?yàn)閮蓚€(gè)表之間關(guān)聯(lián)越緊密,意味著對(duì)「join」和「transaction」的需求越多,所以堅(jiān)持這個(gè)原則可以使得相同的模塊,緊密相關(guān)的業(yè)務(wù)都落在同一個(gè)庫(kù)中,這樣它們可以繼續(xù)使用「join」和「transaction」來(lái)工作。

因此,我們應(yīng)當(dāng)優(yōu)采用「垂直切分」的方式。

做「垂直切分」思路很簡(jiǎn)單,一般情況下,建議是與切分后的應(yīng)用程序一一對(duì)應(yīng)就好,不用多也不用少。

分布式數(shù)據(jù)庫(kù)拆分的常用辦法是什么

實(shí)際工作中,要做好「垂直切分」主要體現(xiàn)在「業(yè)務(wù)」的熟悉度上,所以這里就不繼續(xù)展開(kāi)了。

「垂直切分」的優(yōu)點(diǎn)是:

1.高內(nèi)聚,拆分規(guī)則清晰。相比「水平切分」數(shù)據(jù)冗余度更低。

2.與應(yīng)用程序是1:1的關(guān)系,方便維護(hù)和定位問(wèn)題。一旦某個(gè)數(shù)據(jù)庫(kù)中發(fā)現(xiàn)異常數(shù)據(jù),排查這個(gè)數(shù)據(jù)庫(kù)的關(guān)聯(lián)程序就行了。

但是這并不是一個(gè)「一勞永逸」的方案,因?yàn)闆](méi)人能預(yù)料到未來(lái)業(yè)務(wù)會(huì)發(fā)展的怎么樣,所以最明顯的缺點(diǎn)就是:對(duì)于訪問(wèn)極其頻繁或者數(shù)據(jù)量超大的表仍然存在性能瓶頸。

確實(shí)需要解決這個(gè)問(wèn)題的話,就需要搬出「水平切分」了。

題外話:不到迫不,盡量避免進(jìn)行「水平切分」。看完接下去的內(nèi)容你就知道原因了。

下面Z哥就給你好好聊聊「水平切分」,這才是本文的重點(diǎn)。

水平切分

想象一下,在你做了「垂直切分」之后,還是在某個(gè)數(shù)據(jù)庫(kù)中發(fā)現(xiàn)了一張數(shù)據(jù)量超過(guò)10億條的表。

這個(gè)時(shí)候要對(duì)這個(gè)表做「水平切分」,你會(huì)怎么思考這個(gè)事情?

Z哥教給你的思路是:

  1. 先找到“最高頻“的「讀」字段

  2. 再看這個(gè)字段的實(shí)際使用中有什么特點(diǎn)(批量查詢(xún)多還是單個(gè)查詢(xún)多,是否同時(shí)是其它表的關(guān)聯(lián)字段等等)。

  3. 再根據(jù)這個(gè)特點(diǎn)選擇合適的切分方案。

為什么要先找到高頻的「讀」字段呢?

因?yàn)樵趯?shí)際的使用中,「讀」操作往往是遠(yuǎn)大于「寫(xiě)」操作的。一般進(jìn)行「寫(xiě)」之前都得通過(guò)「讀」來(lái)做先行校驗(yàn),然而「讀」還有自己?jiǎn)为?dú)的使用場(chǎng)景。所以針對(duì)更高頻的「讀」場(chǎng)景去考慮,產(chǎn)生的價(jià)值必然也更大。

 

order (orderId long, createTime datetime, userId long)

下面我們先來(lái)看看有哪幾種「水平切分」的方式,完了才能明白什么樣的場(chǎng)景適合哪種方式。

范圍切分

這是一種「連續(xù)式」的切分方式。

比如根據(jù)時(shí)間(createTime)切分的話,我們可以按年月來(lái)分,order_201901一個(gè)庫(kù),order_201902一個(gè)庫(kù),以此類(lèi)推。

根據(jù)順序數(shù)(orderId)切分的話,可以100000~199999一個(gè)庫(kù),200000~299999一個(gè)庫(kù),以此類(lèi)推。

這種切分法的優(yōu)點(diǎn)是:單個(gè)表的大小可控,擴(kuò)展的時(shí)候無(wú)需數(shù)據(jù)遷移。

缺點(diǎn)也很明顯,一般來(lái)說(shuō)時(shí)間越近或者序號(hào)越大的數(shù)據(jù)越“新”,因此被訪問(wèn)的頻率和概率相比“老”數(shù)據(jù)更多。會(huì)導(dǎo)致壓力主要集中在新的庫(kù)中,而歷史越久的庫(kù),越空閑。

Hash切分

與「范圍切分」正好相反,這是一種「離散式」的切分方式。

它的優(yōu)點(diǎn)就是解決了「范圍切分」的缺點(diǎn),新數(shù)據(jù)被分散到了各個(gè)節(jié)點(diǎn)中,避免了壓力集中在少數(shù)節(jié)點(diǎn)上。

同樣,缺點(diǎn)與「范圍切分」的優(yōu)點(diǎn)相反,一旦進(jìn)行二次擴(kuò)展,必然會(huì)涉及到數(shù)據(jù)遷移。因?yàn)镠ash算法是固定的,算法一變,數(shù)據(jù)分布就變了。

大多數(shù)情況下,我們的hash算法可以通過(guò)簡(jiǎn)單的「取?!惯\(yùn)算來(lái)進(jìn)行即可。就像下面這樣:

假如分成11個(gè)庫(kù)的話,公式就是 orderId % 10。

100000 % 10 = 0,分配到db0。

100001 % 10 = 1,分配到db1。

....

100010 % 10 = 0,分配到db0。

100011 % 10 = 1,分配到db1。

其實(shí),在某些場(chǎng)景下,我們可以通過(guò)自定義id的生成(可以參考之前的文章,《分布式系統(tǒng)中的必備良藥 —— 全局唯一單據(jù)號(hào)生成》)來(lái)做到既可以通過(guò)hash切分來(lái)打散熱點(diǎn)數(shù)據(jù),又可以減少依賴(lài)全局表來(lái)定位具體的數(shù)據(jù)。

比如,在orderId中加入userId的尾數(shù),以此達(dá)到orderId和userId取模結(jié)果相等的效果。還是來(lái)舉個(gè)例子:

一個(gè)用戶(hù)的userId是200004,如果取一個(gè)4bit尾數(shù)的話,這里就是4,用0100表示。

然后,我們通過(guò)自定義id算法生成orderId的前60位,在后面補(bǔ)上0100。

于是,orderId % 10和 userId % 10的結(jié)果就是一樣的了。

當(dāng)然,除了userId之外還想加入其他的因子就不好使了。也就是,可以在不增加全局表的情況下,額外多支持1個(gè)維度。

提到了兩次全局表,那么啥是全局表呢?

全局表

這種方式就是將用作切分依據(jù)的分區(qū)Key與對(duì)應(yīng)的每一條具體數(shù)據(jù)的id保存到一個(gè)單獨(dú)的庫(kù)或者表中。例如要增加一張這樣的表:

3 02 100002

4 01 100003

5 01 100004...

6 ...

如此一來(lái),的確將大部分具體的數(shù)據(jù)分布在了不同服務(wù)器上,但是這張全局表會(huì)給人一種「形散神不散」的感覺(jué)。

因?yàn)檎?qǐng)求數(shù)據(jù)的時(shí)候無(wú)法直接定位需要的數(shù)據(jù)在哪臺(tái)服務(wù)器上,所以每一次操作都要先查詢(xún)一下這張全局表好知道具體的數(shù)據(jù)被存放在哪里。

這種「中心化」的模式帶來(lái)的副作用就是瓶頸和風(fēng)險(xiǎn)轉(zhuǎn)移到了這張全局表上。但是,勝在邏輯簡(jiǎn)單。

好了,那么這幾種切分方案怎么選呢?

Z哥給你的建議是,如果熱點(diǎn)數(shù)據(jù)不是特別集中的場(chǎng)景,建議先用「范圍切分」,否則選擇另外2種

選擇另外兩種的時(shí)候,數(shù)據(jù)量越大越傾向選擇Hash切分。因?yàn)楹笳咴谡w的可用性和性能上都比前者好,就是實(shí)現(xiàn)成本高一些。

「水平切分」真正做到了可以“無(wú)限擴(kuò)展”,但是也存在相應(yīng)的弊端。

1)批量查詢(xún)、分頁(yè)等需要做更多的額外工作。特別是當(dāng)一個(gè)表存在多個(gè)高頻字段用于where、order by或者group by的時(shí)候。

2)拆分規(guī)則不如「垂直切分」那么明確。

所以還是多說(shuō)一句“廢話”:沒(méi)有完美的方案只有合適的方案,要結(jié)合具體的場(chǎng)景來(lái)選擇。(歡迎你在留言區(qū)提出你有疑惑的場(chǎng)景,和Z哥來(lái)討論討論)

如何實(shí)施

當(dāng)你在具體實(shí)施「水平切分」的時(shí)候可以在2個(gè)層面動(dòng)刀,可以是「表」層面,也可以是「庫(kù)」層面。

在同一個(gè)數(shù)據(jù)庫(kù)下面分表,表名order_0 ,order_1, order_2.....。

它可以解決單表數(shù)據(jù)過(guò)大,但并不能解決CPU負(fù)荷的問(wèn)題。所以,當(dāng)CPU并沒(méi)多少壓力,只是由于表太大,導(dǎo)致執(zhí)行SQL操作比較慢的話,可以選擇這種方式。

庫(kù)

這個(gè)時(shí)候表名可以不變,都叫order,只是分成10個(gè)庫(kù)。那么就是db0-user db1-user db2-user......。

我們前面大篇幅都是基于這個(gè)模式在聊,就不多說(shuō)了。

表+庫(kù)

也可以既分庫(kù)又分表,比如先分10個(gè)庫(kù),然后每個(gè)庫(kù)再分10張表。

這其實(shí)是個(gè)二級(jí)索引的思路,通過(guò)庫(kù)來(lái)進(jìn)行第一次定位,減少一定的資源消耗。

比如,先按年分庫(kù),再按月分表。如此一來(lái),如果需要獲取的數(shù)據(jù)只跨月但不跨年,我們就可以在單個(gè)庫(kù)內(nèi)做聚合運(yùn)算來(lái)完成,不涉及到跨庫(kù)操作。

不過(guò),不管選擇哪種方式來(lái)進(jìn)行,你還是會(huì)或多或少面臨以下兩個(gè)問(wèn)題,逃不掉的。

  1. 跨庫(kù)join。

  2. 全局聚合或者排序操作。

解決第一個(gè)問(wèn)題最佳方式還是需要改變你的編程思維。盡量將一些邏輯、關(guān)系、約束等體現(xiàn)在應(yīng)用程序的代碼中,避免因?yàn)榉奖愣赟QL中做這些事情。

畢竟代碼是可以寫(xiě)成“無(wú)狀態(tài)”的,可以隨時(shí)做擴(kuò)展,但是SQL是跟著數(shù)據(jù)走的,而數(shù)據(jù)就是“狀態(tài)”,天然不利于擴(kuò)展。

當(dāng)然了,退而求其次,你也可以冗余大量的全局表來(lái)應(yīng)對(duì)。只是如此一來(lái),對(duì)「數(shù)據(jù)一致性」工作是個(gè)很大的考驗(yàn),另外,對(duì)存儲(chǔ)資源也是很大的開(kāi)銷(xiāo)。

第二個(gè)問(wèn)題的解決方案就是需要將原本的一次聚合或者一次排序變成兩次操作。其中的遍歷多個(gè)節(jié)點(diǎn)可以以「并行」的方式進(jìn)行。

分布式數(shù)據(jù)庫(kù)拆分的常用辦法是什么

那么數(shù)據(jù)切分完之后程序如何來(lái)使用呢?這又可以分為兩種模式,「進(jìn)程內(nèi)」和「進(jìn)程外」。

「進(jìn)程內(nèi)」的話,可以在封裝好的DAL訪問(wèn)框架中做,也可以在ORM框架中做,還可以在數(shù)據(jù)庫(kù)驅(qū)動(dòng)中做。這個(gè)模式比較知名的解決方案如阿里的tddl。

分布式數(shù)據(jù)庫(kù)拆分的常用辦法是什么

「進(jìn)程外」的話,就是代理模式,這個(gè)模式比較知名的解決方案是mycat、cobar、atlas等等,相對(duì)多一些,因?yàn)檫@種模式對(duì)應(yīng)用程序是「低侵入」的,使用起來(lái)像“一個(gè)數(shù)據(jù)庫(kù)”。但是由于多了一道網(wǎng)絡(luò)通信,性能上會(huì)多一些損耗。

老規(guī)矩,下面再分享一些最佳實(shí)踐。

最佳實(shí)踐

首先分享兩個(gè)可以不停機(jī)做數(shù)據(jù)切分的小竅門(mén)。我們以實(shí)施hash法做水平切分的例子來(lái)看一下。

第一次做切分的時(shí)候,你可以以「主-從」的形式將新增的節(jié)點(diǎn)作為原始節(jié)點(diǎn)的副本,進(jìn)行全量實(shí)時(shí)同步。

分布式數(shù)據(jù)庫(kù)拆分的常用辦法是什么

然后在這個(gè)基礎(chǔ)上刪除不屬于它的數(shù)據(jù)。(當(dāng)然了,不刪也沒(méi)啥問(wèn)題,就是多占用一些空間)

分布式數(shù)據(jù)庫(kù)拆分的常用辦法是什么

這樣就可以不用停機(jī)了。

第二,隨著時(shí)間的推移,如果后續(xù)支撐住了,需要二次切分的話,我們可以選擇用2的倍數(shù)來(lái)擴(kuò)展。

如此一來(lái),數(shù)據(jù)的遷移變得很簡(jiǎn)單,只需要做局部的遷移,和第一次做切分的思路是一樣的。

分布式數(shù)據(jù)庫(kù)拆分的常用辦法是什么

當(dāng)然了,如果選擇的切分方式是「范圍切分」的話,就沒(méi)有二次切分時(shí)的困擾,數(shù)據(jù)自然跑到最新的節(jié)點(diǎn)上去了。比如我們按年月分表的話。2019年3月的數(shù)據(jù)自然就落到了xxxx_201903的表中。

到這里,Z哥還是想特別強(qiáng)調(diào)的是,能不切分盡量不要切分,可以先使用「讀寫(xiě)分離」之類(lèi)的方案先來(lái)應(yīng)對(duì)面臨的問(wèn)題。

如果實(shí)在要進(jìn)行切分的話,務(wù)必先「垂直切分」,再考慮「水平切分」。

一般來(lái)說(shuō),以這樣的順序來(lái)考慮,性?xún)r(jià)比更好。

看完上述內(nèi)容,你們對(duì)分布式數(shù)據(jù)庫(kù)拆分的常用辦法是什么有進(jìn)一步的了解嗎?如果還想了解更多知識(shí)或者相關(guān)內(nèi)容,請(qǐng)關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝大家的支持。

當(dāng)前標(biāo)題:分布式數(shù)據(jù)庫(kù)拆分的常用辦法是什么
URL分享:http://muchs.cn/article40/gphoho.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供軟件開(kāi)發(fā)網(wǎng)站建設(shè)、關(guān)鍵詞優(yōu)化云服務(wù)器、響應(yīng)式網(wǎng)站外貿(mào)網(wǎng)站建設(shè)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶(hù)投稿、用戶(hù)轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

h5響應(yīng)式網(wǎng)站建設(shè)