關(guān)于分庫(kù)分表策略的分析和總結(jié)

一.分庫(kù)分表的原因

我個(gè)人覺得原因其實(shí)很簡(jiǎn)單:
1.隨著單庫(kù)中的數(shù)據(jù)量越來(lái)越大,相應(yīng)的咱士,查詢所需要的時(shí)間也越來(lái)越多循帐,而面對(duì)MySQL這樣的數(shù)據(jù)庫(kù),在進(jìn)行添加一列這樣的操作時(shí)會(huì)有鎖表的操作陷谱,期間所有的讀寫操作都要等待,這個(gè)時(shí)候瑟蜈,相當(dāng)于數(shù)據(jù)的處理遇到了瓶頸
2.其實(shí)就是有意外發(fā)生的時(shí)候,單庫(kù)發(fā)生意外的時(shí)候渣窜,需要修復(fù)的是所有的數(shù)據(jù)铺根,而多庫(kù)中的一個(gè)庫(kù)發(fā)生意外的時(shí)候,只需要修復(fù)一個(gè)庫(kù)(當(dāng)然乔宿,也可以用物理分區(qū)的方式處理這種問題)

二.分庫(kù)分表常用的策略

在我網(wǎng)上搜集的過(guò)程中位迂,以及自己的實(shí)踐,得到的分庫(kù)策略可以簡(jiǎn)單分為以下幾種方式:(如果有不正確的地方详瑞,請(qǐng)大家給我指出來(lái)掂林,萬(wàn)分感謝)
首先,分為垂直切分和水平切分:
先說(shuō)垂直切分吧坝橡,我的認(rèn)為是根據(jù)業(yè)務(wù)的不同泻帮,將原先擁有很多字段的表拆分為兩個(gè)或者多個(gè)表,這樣的代價(jià)我個(gè)人覺得很大计寇,原來(lái)對(duì)這應(yīng)這個(gè)表的關(guān)系锣杂,開始細(xì)分脂倦,需要一定的重構(gòu),而且隨著數(shù)據(jù)量的增多元莫,極有可能還要增加水平切分赖阻;
水平切分,數(shù)據(jù)表結(jié)構(gòu)踱蠢,將數(shù)據(jù)分散在多個(gè)表中火欧;



簡(jiǎn)單的示意圖的了解一下。
對(duì)于垂直切分茎截,好像能說(shuō)的并不多布隔,說(shuō)的比較多一點(diǎn)的是水平切分。
水平切分時(shí)候稼虎,理想的情況是不進(jìn)行數(shù)據(jù)遷移衅檀,無(wú)感知的進(jìn)行,當(dāng)然這就需要一點(diǎn)點(diǎn)小小的分庫(kù)分表的策略霎俩。

1.有瑕疵的簡(jiǎn)單分庫(kù)分表(按id的大小分庫(kù)分表)

按照分片鍵(我們這里就用id表示了)的大小來(lái)進(jìn)行分庫(kù)分表哀军,如果你的id是自增的,而且能保證在進(jìn)行分庫(kù)分表后也是自增的打却,那么能進(jìn)行很好的改造杉适,以id大小水平切分,而且極有可能不用遷移數(shù)據(jù)柳击。

按id大小分庫(kù).PNG

當(dāng)然猿推,這里只列舉了比較小的數(shù)據(jù)量,實(shí)際情況的分庫(kù)的界限還是要依據(jù)具體的情況而定捌肴。這樣的分庫(kù)分表蹬叭,因?yàn)樾碌臄?shù)據(jù)總在一個(gè)庫(kù)里,很可能導(dǎo)致熱點(diǎn)過(guò)于集中(讀寫可能集中在一個(gè)庫(kù)中)状知,這是采取這種方式需要考慮的事情秽五。
如果無(wú)法保證你的id是自增長(zhǎng)的,那么你的數(shù)據(jù)就會(huì)凌亂的分散在各個(gè)數(shù)據(jù)庫(kù)饥悴,這樣熱點(diǎn)確實(shí)就分散了坦喘,可是每當(dāng)你增加一個(gè)數(shù)據(jù)庫(kù)的時(shí)候,你就有可能進(jìn)行大量的數(shù)據(jù)遷移西设,應(yīng)對(duì)這種情況瓣铣,就是盡量減少數(shù)據(jù)遷移的代價(jià),所以這里運(yùn)用一致性hash的方式進(jìn)行分庫(kù)分表比較好贷揽,可以盡可能的減少數(shù)據(jù)遷移棠笑,并且也能讓解決熱點(diǎn)過(guò)于集中的問題。一致性hash的分庫(kù)策略去百度一下或者谷歌一下應(yīng)該很容易搜到。如果你百度了還是不知道涡戳,歡迎你來(lái)跟我討論芥颈。
這里按id的大小來(lái)分庫(kù)审胸,還可以發(fā)散到按照時(shí)間來(lái)分庫(kù)阿弃,比如說(shuō)一個(gè)月的數(shù)據(jù)放在一個(gè)庫(kù)江咳,這個(gè)使用mycat比較容易實(shí)現(xiàn)按時(shí)間分庫(kù)晒哄,不過(guò)你需要思考的數(shù)據(jù)的離散性被芳,數(shù)據(jù)集中于一個(gè)兩月巨柒,而剩下的幾個(gè)月數(shù)據(jù)稀疏樱拴,這樣的又可能需要按照數(shù)據(jù)的生產(chǎn)規(guī)律合并幾個(gè)月到一個(gè)庫(kù)中,使得數(shù)據(jù)分布均勻洋满。

2.比較方便的取模分庫(kù)

一般的取模分庫(kù)分表是就是將id mod n晶乔,然后放入數(shù)據(jù)庫(kù)中,這樣能夠使數(shù)據(jù)分散牺勾,不會(huì)有熱點(diǎn)的問題正罢,那么,剩下的是驻民,在擴(kuò)容的時(shí)候翻具,是否會(huì)有數(shù)據(jù)遷移的問題,一般的擴(kuò)容回还,當(dāng)然是會(huì)有數(shù)據(jù)遷移的裆泳。

取模.PNG

例子中,對(duì)3取模柠硕,當(dāng)需要擴(kuò)容的時(shí)候(假設(shè)增加兩個(gè)庫(kù))工禾,則對(duì)5取模,這樣的結(jié)果必然是要進(jìn)行數(shù)據(jù)遷移的蝗柔,但是可以運(yùn)用一些方法闻葵,讓它不進(jìn)行數(shù)據(jù)遷移,scale-out擴(kuò)展方案能夠避免在取模擴(kuò)容的時(shí)候進(jìn)行數(shù)據(jù)遷移诫咱。這個(gè)方案是我看到的笙隙,我個(gè)人覺得很好的方案了,這是原文坎缭。
我也想介紹一下這個(gè)方案(主要想檢測(cè)一下自己理解了沒):

(1)第一種擴(kuò)容的方式:根據(jù)表的數(shù)據(jù)增加庫(kù)的數(shù)量

首先,我們有一個(gè)數(shù)據(jù)庫(kù)——DB_0,四張表——tb_0,tb_1,tb_2,tb_3
那么我們現(xiàn)在數(shù)據(jù)到數(shù)據(jù)庫(kù)是這樣的:
DB="DB_0"
TB=“tb_"+id%4



當(dāng)數(shù)據(jù)增加签钩,需要進(jìn)行擴(kuò)容的時(shí)候掏呼,我增加一個(gè)數(shù)據(jù)庫(kù)DB_1
DB="DB_"+((id%4)/2)
TB=“tb_"+id%4



當(dāng)我們的數(shù)據(jù)繼續(xù)飆升,這個(gè)時(shí)候又需要我們?cè)黾訋?kù)铅檩,這個(gè)時(shí)候進(jìn)行加庫(kù)操作的時(shí)候憎夷,就不是增加一個(gè)庫(kù),而必須是兩個(gè)昧旨,這樣才能保證不進(jìn)行數(shù)據(jù)遷移拾给。
DB="DB_"+id%4
TB=“tb_"+id%4

這個(gè)時(shí)候到了這個(gè)方案的加庫(kù)上限祥得,不能繼續(xù)加庫(kù)了,否則就要進(jìn)行數(shù)據(jù)遷移蒋得,所以這個(gè)方案的弊端還是挺大了级及,這樣的方式,也應(yīng)該會(huì)造成單表的數(shù)據(jù)量挺大的额衙。

(2)第二種擴(kuò)容的方式:成倍的增加表

首先饮焦,我們還是一個(gè)數(shù)據(jù)庫(kù)——DB_0,兩張表——tb_0,tb_1
那么我們現(xiàn)在數(shù)據(jù)到數(shù)據(jù)庫(kù)是這樣的:
DB="DB_0"
TB=“tb_"+id%2



假設(shè)當(dāng)我們數(shù)據(jù)量打到一千萬(wàn)的時(shí)候,我們?cè)黾右粋€(gè)庫(kù)窍侧,這時(shí)需要我們?cè)黾觾蓮埍韙b_0_1,tb_1_1,并且原來(lái)的DB_0中庫(kù)的表tb_1整表遷移到DB_1中县踢,tb_0和tb_0_1放在DB_0中,tb_1和tb_1_1放到DB1中伟件。
DB="DB_"+id%2
tb:
if(id<1千萬(wàn)) { return "tb_" + id % 2 }
else if(id>=1千萬(wàn)) { return "tb_"+ id % 2 + "_1" }


數(shù)據(jù)的增長(zhǎng)不可能到此為止硼啤,當(dāng)增加到兩千萬(wàn)的時(shí)候,我們需要加庫(kù)斧账,這個(gè)時(shí)候谴返,按照這種做法,我們需要增加兩個(gè)庫(kù)(DB_2,DB_3)和四張表(tb_0_2,tb_1_2,tb_2_2,tb_3_2)其骄,將上次新增的表整表分別放進(jìn)兩個(gè)新的庫(kù)中亏镰,然后每個(gè)庫(kù)里再生成一張新表。
DB:
if(id < 1千萬(wàn)) { return "DB_" + id % 2 }
else if(1千萬(wàn) <= id < 2千萬(wàn)) { return "DB_"+ id % 2 +2 }
else if(2千萬(wàn) <= id ) { return "DB_"+ id % 4 }
tb:
if(id < 1千萬(wàn)) { return "tb_" + id % 2 }
else if(1千萬(wàn) <= id < 2千萬(wàn)) { return "tb_"+ id % 2 +"1" }
else if(id >= 2千萬(wàn)) { return "tb
"+ id % 4+"_2" }

值得注意的一點(diǎn)拯爽,在id超出范圍的時(shí)候索抓,該給怎么樣的提示是值得思考的。

(3)第二種擴(kuò)容的方式:一個(gè)一個(gè)的增加毯炮。(我在這里和原文有點(diǎn)出入逼肯,大家不看也罷)

上一種方式是成倍的增加,有的時(shí)候往往不需要這樣桃煎,現(xiàn)在我們基于上一個(gè)例子的第二階段(1千萬(wàn)到2千萬(wàn)的階段)篮幢,添加一個(gè)庫(kù)DB_2,新增兩張表tb_0_2,tb_1_2;將tb_0和tb_1放在DB_0中,最為舊文件的查詢为迈,tb_0_1和和tb_1_1分別放入DB_1和DB_2中三椿,再在這兩個(gè)庫(kù)中生成新的表
DB:
if(id < 1千萬(wàn)) { return "DB_0"}
else if(1千萬(wàn) <= id < 2千萬(wàn)) { return "DB_"+ (id % 2 + 1)
else if(id >= 2千萬(wàn)) {return "DB_"+ id%3}
tb:
if(id < 1千萬(wàn)) { return "tb_" + id%2}
else if(1千萬(wàn) <= id < 2千萬(wàn)) { return "tb_"+ (id % 2) +”1“
else if(id >= 2千萬(wàn)) {return "DB
"+ id%2 +"_0"}


第三種擴(kuò)展方式,按照原文的介紹葫辐,會(huì)在舊的數(shù)據(jù)庫(kù)中加入新的數(shù)據(jù)庫(kù)搜锰,而且當(dāng)繼續(xù)擴(kuò)容的時(shí)候,也會(huì)又一定的困難耿战,我這樣的方式蛋叼,對(duì)于新的擴(kuò)容,比較困難,所以第三種方式總的來(lái)說(shuō)是我認(rèn)為是失敗狈涮,我個(gè)人覺得最優(yōu)的方式是第二種狐胎,我這里的id>n是指在數(shù)據(jù)量達(dá)到n這個(gè)數(shù)據(jù)量,而不是指id按大小進(jìn)行比較歌馍,那樣的話握巢,和按照id大小進(jìn)行擴(kuò)容又什么區(qū)別,哈哈哈骆姐。
總得來(lái)說(shuō)镜粤,對(duì)于數(shù)據(jù)庫(kù)擴(kuò)容,總得思考方向?yàn)閮牲c(diǎn):一個(gè)是是否進(jìn)行數(shù)據(jù)遷移玻褪;一個(gè)是數(shù)據(jù)是否分布均勻肉渴,會(huì)不會(huì)造成熱點(diǎn)集中的情況。數(shù)據(jù)遷移也不一定是壞的带射,這些都依據(jù)場(chǎng)景而定同规。

二.分庫(kù)分表后的考慮

分庫(kù)分表之后常常會(huì)遇到數(shù)據(jù)分頁(yè)的問題,這個(gè)問題其實(shí)解決的辦法很多窟社,但是都沒有一個(gè)完美的方法券勺,總的來(lái)說(shuō),還是需要妥協(xié)灿里,例如在不分庫(kù)分表前:select * from t_msg order by time offset 200 limit 100 這樣的語(yǔ)句关炼,在分庫(kù)分表的后,我看到的有這樣幾種處理
方法一:全局視野法(分別從各個(gè)庫(kù)中提取到x+Y的數(shù)據(jù)量進(jìn)行排序提认坏酢)
將order by time offset X limit Y儒拂,改寫成order by time offset 0 limit X+Y。
服務(wù)層對(duì)得到的N*(X+Y)條數(shù)據(jù)進(jìn)行內(nèi)存排序色鸳,內(nèi)存排序后再取偏移量X后的Y條記錄社痛。
方法二:業(yè)務(wù)折衷法-禁止跳頁(yè)查詢
用正常的方法取得第一頁(yè)數(shù)據(jù),并得到第一頁(yè)記錄的time_max命雀。
每次翻頁(yè)蒜哀,將order by time offset X limit Y,改寫成order by time where time>$time_max limit Y以保證每次只返回一頁(yè)數(shù)據(jù)吏砂,性能為常量撵儿。
方法三:業(yè)務(wù)折衷法-允許模糊數(shù)據(jù)(數(shù)據(jù)分布足夠隨機(jī)的情況下,各分庫(kù)所有非patition key屬性狐血,在各個(gè)分庫(kù)上的數(shù)據(jù)分布统倒,統(tǒng)計(jì)概率情況應(yīng)該是一致的)
將order by time offset X limit Y,改寫成order by time offset X/N limit Y/N氛雪。
方法四:二次查詢法
將order by time offset X limit Y,改寫成order by time offset X/N limit Y耸成;
找到最小值time_min报亩;
between二次查詢浴鸿,order by time between $$time_min and $time_i_max;
設(shè)置虛擬time_min弦追,找到time_min在各個(gè)分庫(kù)的offset岳链,從而得到time_min在全局的offset;
得到了time_min在全局的offset劲件,自然得到了全局的offset X limit Y掸哑。

最后我想說(shuō),不同的業(yè)務(wù)場(chǎng)景對(duì)應(yīng)不同的策略零远,不能為了追求最新的東西苗分,而忽略真正的業(yè)務(wù)場(chǎng)景,這樣的得不償失牵辣。任何一件事都具有兩面性摔癣,就看你如何取舍,放之四海而皆準(zhǔn)纬向。不管什么事情都能解決的择浊,所以,遇到問題不要慌逾条。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末琢岩,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子师脂,更是在濱河造成了極大的恐慌担孔,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,542評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件危彩,死亡現(xiàn)場(chǎng)離奇詭異攒磨,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)汤徽,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門娩缰,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人谒府,你說(shuō)我怎么就攤上這事拼坎。” “怎么了完疫?”我有些...
    開封第一講書人閱讀 163,912評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵泰鸡,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我壳鹤,道長(zhǎng)盛龄,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,449評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮余舶,結(jié)果婚禮上啊鸭,老公的妹妹穿的比我還像新娘。我一直安慰自己匿值,他們只是感情好赠制,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,500評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著挟憔,像睡著了一般钟些。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上绊谭,一...
    開封第一講書人閱讀 51,370評(píng)論 1 302
  • 那天政恍,我揣著相機(jī)與錄音,去河邊找鬼龙誊。 笑死抚垃,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的趟大。 我是一名探鬼主播鹤树,決...
    沈念sama閱讀 40,193評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼逊朽!你這毒婦竟也來(lái)了罕伯?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,074評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤叽讳,失蹤者是張志新(化名)和其女友劉穎追他,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體岛蚤,經(jīng)...
    沈念sama閱讀 45,505評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡邑狸,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,722評(píng)論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了涤妒。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片单雾。...
    茶點(diǎn)故事閱讀 39,841評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖她紫,靈堂內(nèi)的尸體忽然破棺而出硅堆,到底是詐尸還是另有隱情,我是刑警寧澤贿讹,帶...
    沈念sama閱讀 35,569評(píng)論 5 345
  • 正文 年R本政府宣布渐逃,位于F島的核電站,受9級(jí)特大地震影響民褂,放射性物質(zhì)發(fā)生泄漏茄菊。R本人自食惡果不足惜疯潭,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,168評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望买羞。 院中可真熱鬧袁勺,春花似錦、人聲如沸畜普。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)吃挑。三九已至,卻和暖如春街立,著一層夾襖步出監(jiān)牢的瞬間舶衬,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工赎离, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留逛犹,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,962評(píng)論 2 370
  • 正文 我出身青樓梁剔,卻偏偏與公主長(zhǎng)得像虽画,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子荣病,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,781評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容