一次難得的分庫分表實(shí)踐

背景

前不久發(fā)過兩篇關(guān)于分表的文章:

從標(biāo)題可以看得出來株旷,當(dāng)時(shí)我們只做了分表脖母;還是由于業(yè)務(wù)發(fā)展疆导,截止到現(xiàn)在也做了分庫蟆沫,目前看來都還比較順利,所以借著腦子還記得清楚來一次復(fù)盤蛾洛。

先來回顧下整個(gè)分庫分表的流程如下:

整個(gè)過程也很好理解养铸,基本符合大部分公司的一個(gè)發(fā)展方向。

很少會有業(yè)務(wù)一開始就會設(shè)計(jì)為分庫分表轧膘,雖說這樣會減少后續(xù)的坑钞螟,但部分公司剛開始都是以業(yè)務(wù)為主。

直到業(yè)務(wù)發(fā)展到單表無法支撐時(shí)谎碍,自然而然會考慮分表甚至分庫的事情筛圆。

于是本篇會作一次總結(jié),之前提過的內(nèi)容可能會再重復(fù)一次椿浓。

分表

首先討論下什么樣的情況下適合分表?

根據(jù)我的經(jīng)驗(yàn)來看闽晦,當(dāng)某張表的數(shù)據(jù)量已經(jīng)達(dá)到千萬甚至上億扳碍,同時(shí)日增數(shù)據(jù)量在 2% 以上。

當(dāng)然這些數(shù)字并不是絕對的仙蛉,最重要的還是對這張表的寫入和查詢都已經(jīng)影響到正常業(yè)務(wù)執(zhí)行笋敞,比如查詢速度明顯下降,數(shù)據(jù)庫整體 IO 居高不下等荠瘪。

而談到分表時(shí)我們著重討論的還是水平分表夯巷;

也就是將一張大表數(shù)據(jù)通過某種路由算法將數(shù)據(jù)盡可能的均勻分配到 N 張小表中。

Range

而分表策略也有好幾種哀墓,分別適用不同的場景趁餐。

首先第一種是按照范圍劃分,比如我們可以將某張表的創(chuàng)建時(shí)間按照日期劃分存為月表篮绰;也可以將某張表的主鍵按照范圍劃分后雷,比如 【110000】在一張表,【1000120000】在一張表吠各,以此類推臀突。

這樣的分表適合需要對數(shù)據(jù)做歸檔處理,比如系統(tǒng)默認(rèn)只提供近三個(gè)月歷史數(shù)據(jù)的查詢功能贾漏,這樣也方便操作候学;只需要把三月之前的數(shù)據(jù)單獨(dú)移走備份保存即可)。

這個(gè)方案有好處也有弊端:

  • 好處是自帶水平擴(kuò)展纵散,不需要過多干預(yù)梳码。
  • 缺點(diǎn)是可能會出現(xiàn)數(shù)據(jù)不均勻的情況(比如某個(gè)月請求暴增)隐圾。

Hash

按照日期這樣的范圍分表固然簡單,但適用范圍還是比較窄边翁;畢竟我們大部分的數(shù)據(jù)查詢都不想帶上時(shí)間翎承。

比如某個(gè)用戶想查詢他產(chǎn)生的所有訂單信息,這是很常見的需求符匾。

于是我們分表的維度就得改改叨咖,分表算法可以采用主流的 hash+mod 的組合。

這是一個(gè)經(jīng)典的算法啊胶,大名鼎鼎的 HashMap 也是這樣來存儲數(shù)據(jù)甸各。

假設(shè)我們這里將原有的一張大表訂單信息分為 64 張分表:

這里的 hash 便是將我們需要分表的字段進(jìn)行一次散列運(yùn)算,使得經(jīng)過散列的數(shù)據(jù)盡可能的均勻并且不重復(fù)焰坪。

當(dāng)然如果本身這個(gè)字段就是一個(gè)整形并且不重復(fù)也可以省略這個(gè)步驟趣倾,直接進(jìn)行 Mod 得到分表下標(biāo)即可。

分表數(shù)量選擇

至于這里的分表數(shù)量(64)也是有講究的某饰,具體設(shè)為多少這個(gè)沒有標(biāo)準(zhǔn)值儒恋,需要根據(jù)自身業(yè)務(wù)發(fā)展,數(shù)據(jù)增量進(jìn)行預(yù)估黔漂。

根據(jù)我個(gè)人的經(jīng)驗(yàn)來看诫尽,至少需要保證分好之后的小表在業(yè)務(wù)發(fā)展的幾年之內(nèi)都不會出現(xiàn)單表數(shù)據(jù)量過大(比如達(dá)到千萬級)。

我更傾向于在數(shù)據(jù)庫可接受的范圍內(nèi)盡可能的增大這個(gè)分表數(shù)炬守,畢竟如果后續(xù)小表也達(dá)到瓶頸需要再進(jìn)行一次分表擴(kuò)容牧嫉,那是非常痛苦的。

目前筆者還沒經(jīng)歷這一步减途,所以本文沒有相關(guān)介紹酣藻。

但是這個(gè)數(shù)量又不是瞎選的,和 HashMap 一樣鳍置,也建議得是 2^n辽剧,這樣可以方便在擴(kuò)容的時(shí)盡可能的少遷移數(shù)據(jù)。

Range + Hash

當(dāng)然還有一種思路税产,RangeHash 是否可以混用抖仅。

比如我們一開始采用的是 Hash 分表,但是數(shù)據(jù)增長巨大砖第,導(dǎo)致每張分表數(shù)據(jù)很快達(dá)到瓶頸撤卢,這樣就不得不再做擴(kuò)容,比如由 64 張表擴(kuò)容到 256 張梧兼。

但擴(kuò)容時(shí)想要做到不停機(jī)遷移數(shù)據(jù)非常困難放吩,即便是停機(jī),那停多久呢羽杰?也不好說渡紫。

所以我們是否可以在 Mod 分表的基礎(chǔ)上再分為月表到推,借助于 Range 自身的擴(kuò)展性就不用考慮后續(xù)數(shù)據(jù)遷移的事情了。

這種方式理論可行惕澎,但我沒有實(shí)際用過莉测,給大家的思路做個(gè)參考吧。

煩人的數(shù)據(jù)遷移

分表規(guī)則弄好后其實(shí)只是完成了分表的第一步唧喉,真正麻煩的是數(shù)據(jù)遷移捣卤,或者說是如何做到對業(yè)務(wù)影響最小的數(shù)據(jù)遷移。

除非是一開始就做了分表八孝,所以數(shù)據(jù)遷移這一步驟肯定是跑不掉的董朝。

下面整理下目前我們的做法供大家參考:

  1. 一旦分表上線后所有的數(shù)據(jù)寫入、查詢都是針對于分表的干跛,所以原有大表內(nèi)的數(shù)據(jù)必須得遷移到分表里子姜,不然對業(yè)務(wù)的影響極大。
  2. 我們估算了對一張 2 億左右的表進(jìn)行遷移楼入,自己寫的遷移程序哥捕,大概需要花 4~5 天的時(shí)間才能完成遷移。
  3. 意味著這段時(shí)間內(nèi)嘉熊,以前的數(shù)據(jù)對用戶是不可見的遥赚,顯然這樣業(yè)務(wù)不能接受。
  4. 于是我們做了一個(gè)兼容處理:分表改造上線后记舆,所有新產(chǎn)生的數(shù)據(jù)寫入分表,但對歷史數(shù)據(jù)的操作還走老表呼巴,這樣就少了數(shù)據(jù)遷移這一步驟泽腮。
  5. 只是需要在操作數(shù)據(jù)之前做一次路由判斷,當(dāng)新數(shù)據(jù)產(chǎn)生的足夠多時(shí)(我們是兩個(gè)月時(shí)間)衣赶,幾乎所有的操作都是針對于分表诊赊,再從庫啟動(dòng)數(shù)據(jù)遷移,數(shù)據(jù)遷移完畢后將原有的路由判斷去掉府瞄。
  6. 最后所有的數(shù)據(jù)都從分表產(chǎn)生和寫入碧磅。

至此整個(gè)分表操作完成。

業(yè)務(wù)兼容

同時(shí)分表之后還需要兼容其他業(yè)務(wù)遵馆;比如原有的報(bào)表業(yè)務(wù)鲸郊、分頁查詢等,現(xiàn)在來看看我們是如何處理的货邓。

報(bào)表

首先是報(bào)表秆撮,沒分表之前之間查詢一張表就搞定了,現(xiàn)在不同换况,由一張表變?yōu)?N 張表职辨。

所以原有的查詢要改為遍歷所有的分表盗蟆,考慮到性能可以利用多線程并發(fā)查詢分表數(shù)據(jù)然后匯總。

不過只依靠 Java 來對這么大量的數(shù)據(jù)做統(tǒng)計(jì)分析還是不現(xiàn)實(shí)舒裤,剛開始可以應(yīng)付過去喳资,后續(xù)還得用上大數(shù)據(jù)平臺來處理。

查詢

再一個(gè)是查詢腾供,原有的分頁查詢肯定是不能用了仆邓,畢竟對上億的數(shù)據(jù)分頁其實(shí)沒什么意義。

只能提供通過分表字段的查詢台腥,比如是按照訂單 ID 分表宏赘,那查詢條件就得帶上這個(gè)字段,不然就會涉及到遍歷所有表黎侈。

這也是所有分表之后都會遇到的一個(gè)問題察署,除非不用 MySQL 這類關(guān)系型數(shù)據(jù)庫。

分庫

分表完成后可以解決單表的壓力峻汉,但數(shù)據(jù)庫本身的壓力卻沒有下降贴汪。

我們在完成分表之后的一個(gè)月內(nèi)又由于數(shù)據(jù)庫里“其他表”的寫入導(dǎo)致整個(gè)數(shù)據(jù)庫 IO 增加,而且這些“其他表”還和業(yè)務(wù)關(guān)系不大休吠。

也就是說一些可有可無的數(shù)據(jù)導(dǎo)致了整體業(yè)務(wù)受影響扳埂,這是非常不劃算的事情。

于是我們便把這幾張表單獨(dú)移到一個(gè)新的數(shù)據(jù)庫中瘤礁,完全和現(xiàn)有的業(yè)務(wù)隔離開來阳懂。

這樣就會涉及到幾個(gè)改造:

  1. 應(yīng)用自身對這些數(shù)據(jù)的查詢、寫入都要改為調(diào)用一個(gè)獨(dú)立的 Dubbo 服務(wù)柜思,由這個(gè)服務(wù)對遷移的表進(jìn)行操作岩调。
  2. 暫時(shí)不做數(shù)據(jù)遷移,所以查詢時(shí)也得按照分表那樣做一個(gè)兼容赡盘,如果查詢老數(shù)據(jù)就要在當(dāng)前庫查詢号枕,新數(shù)據(jù)就要調(diào)用 Dubbo 接口進(jìn)行查詢。
  3. 對這些表的一些關(guān)聯(lián)查詢也得改造為查詢 Dubbo 接口陨享,在內(nèi)存中進(jìn)行拼接即可葱淳。
  4. 如果數(shù)據(jù)量確實(shí)很大,也可將同步的 Dubbo 接口換為寫入消息隊(duì)列來提高吞吐量抛姑。

目前我們將這類數(shù)據(jù)量巨大但對業(yè)務(wù)不太影響的表單獨(dú)遷到一個(gè)庫后赞厕,數(shù)據(jù)庫的整體 IO 下降明顯,業(yè)務(wù)也恢復(fù)正常定硝。

總結(jié)

最后我們還需要做一步歷史數(shù)據(jù)歸檔的操作坑傅,將 N 個(gè)月之前的數(shù)據(jù)要定期遷移到 HBASE 之類存儲,保證 MySQL 中的數(shù)據(jù)一直保持在一個(gè)可接受的范圍喷斋。

而歸檔數(shù)據(jù)的查詢便依賴于大數(shù)據(jù)提供服務(wù)唁毒。

本次分庫分表是一次非常難得的實(shí)踐操作蒜茴,網(wǎng)上大部分的資料都是在汽車出廠前就換好了輪胎。

而我們大部分碰到的場景都是要對高速路上跑著的車子換胎浆西,一不小心就“車毀人亡”粉私。

有更好的方式方法歡迎大家評論區(qū)留言討論。

你的點(diǎn)贊與分享是對我最大的支持

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末近零,一起剝皮案震驚了整個(gè)濱河市诺核,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌久信,老刑警劉巖窖杀,帶你破解...
    沈念sama閱讀 218,607評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異裙士,居然都是意外死亡入客,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,239評論 3 395
  • 文/潘曉璐 我一進(jìn)店門腿椎,熙熙樓的掌柜王于貴愁眉苦臉地迎上來桌硫,“玉大人,你說我怎么就攤上這事啃炸∶” “怎么了?”我有些...
    開封第一講書人閱讀 164,960評論 0 355
  • 文/不壞的土叔 我叫張陵南用,是天一觀的道長膀钠。 經(jīng)常有香客問我,道長裹虫,這世上最難降的妖魔是什么肿嘲? 我笑而不...
    開封第一講書人閱讀 58,750評論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮恒界,結(jié)果婚禮上睦刃,老公的妹妹穿的比我還像新娘砚嘴。我一直安慰自己十酣,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,764評論 6 392
  • 文/花漫 我一把揭開白布际长。 她就那樣靜靜地躺著耸采,像睡著了一般。 火紅的嫁衣襯著肌膚如雪工育。 梳的紋絲不亂的頭發(fā)上虾宇,一...
    開封第一講書人閱讀 51,604評論 1 305
  • 那天,我揣著相機(jī)與錄音如绸,去河邊找鬼嘱朽。 笑死旭贬,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的搪泳。 我是一名探鬼主播稀轨,決...
    沈念sama閱讀 40,347評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼岸军!你這毒婦竟也來了奋刽?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,253評論 0 276
  • 序言:老撾萬榮一對情侶失蹤艰赞,失蹤者是張志新(化名)和其女友劉穎佣谐,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體方妖,經(jīng)...
    沈念sama閱讀 45,702評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡狭魂,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,893評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了吁断。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片趁蕊。...
    茶點(diǎn)故事閱讀 40,015評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖仔役,靈堂內(nèi)的尸體忽然破棺而出掷伙,到底是詐尸還是另有隱情,我是刑警寧澤又兵,帶...
    沈念sama閱讀 35,734評論 5 346
  • 正文 年R本政府宣布任柜,位于F島的核電站,受9級特大地震影響沛厨,放射性物質(zhì)發(fā)生泄漏宙地。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,352評論 3 330
  • 文/蒙蒙 一逆皮、第九天 我趴在偏房一處隱蔽的房頂上張望宅粥。 院中可真熱鬧,春花似錦电谣、人聲如沸秽梅。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,934評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽企垦。三九已至,卻和暖如春晒来,著一層夾襖步出監(jiān)牢的瞬間钞诡,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,052評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留荧降,地道東北人接箫。 一個(gè)月前我還...
    沈念sama閱讀 48,216評論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像朵诫,于是被迫代替她去往敵國和親列牺。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,969評論 2 355

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