[Mysql]數(shù)據(jù)庫分庫分表

一. 分表

場景:對于大型的互聯(lián)網(wǎng)應(yīng)用來說试幽,數(shù)據(jù)庫單表的記錄行數(shù)可能達(dá)到千萬級甚至是億級萨脑,并且數(shù)據(jù)庫面臨著極高的并發(fā)訪問隐轩。采用Master-Slave復(fù)制模式的MySQL架構(gòu)

只能夠?qū)?shù)據(jù)庫的讀進(jìn)行擴(kuò)展渤早,而對數(shù)據(jù)庫的寫入操作還是集中在Master上职车,并且單個(gè)Master掛載的Slave也不可能無限制多,Slave的數(shù)量受到Master能力和負(fù)載的限制鹊杖。
因此悴灵,需要對數(shù)據(jù)庫的吞吐能力進(jìn)行進(jìn)一步的擴(kuò)展,以滿足高并發(fā)訪問與海量數(shù)據(jù)存儲的需要仅淑!

對于訪問極為頻繁且數(shù)據(jù)量巨大的單表來說称勋,我們首先要做的就是減少單表的記錄條數(shù),以便減少數(shù)據(jù)查詢所需要的時(shí)間涯竟,提高數(shù)據(jù)庫的吞吐,這就是所謂的分表空厌!

在分表之前庐船,首先需要選擇適當(dāng)?shù)姆直聿呗裕沟脭?shù)據(jù)能夠較為均衡地分不到多張表中嘲更,并且不影響正常的查詢筐钟!

對于互聯(lián)網(wǎng)企業(yè)來說,大部分?jǐn)?shù)據(jù)都是與用戶關(guān)聯(lián)的赋朦,因此篓冲,用戶id是最常用的分表字段。因?yàn)榇蟛糠植樵兌夹枰獛嫌脩鬷d宠哄,這樣既不影響查詢壹将,又能夠使數(shù)據(jù)較為均衡地
分布到各個(gè)表中(當(dāng)然,有的場景也可能會出現(xiàn)冷熱數(shù)據(jù)分布不均衡的情況)毛嫉,如下圖:

假設(shè)有一張表記錄用戶購買信息的訂單表order诽俯,由于order表記錄條數(shù)太多,將被拆分成256張表承粤。
拆分的記錄根據(jù)user_id%256取得對應(yīng)的表進(jìn)行存儲暴区,前臺應(yīng)用則根據(jù)對應(yīng)的user_id%256闯团,找到對應(yīng)訂單存儲的表進(jìn)行訪問。
這樣一來仙粱,user_id便成為一個(gè)必需的查詢條件房交,否則將會由于無法定位數(shù)據(jù)存儲的表而無法對數(shù)據(jù)進(jìn)行訪問。

注:拆分后表的數(shù)量一般為2的n次方伐割,就是上面拆分成256張表的由來候味!

假設(shè)order表結(jié)構(gòu)如下:

create table order_(  
 order_id bigint(20) primary key auto_increment,  
 user_id bigint(20),  
 user_nick varchar(50),  
 auction_id bigint(20),  
 auction_title bigint(20),  
 price bigint(20),  
 auction_cat varchar(200),  
 seller_id bigint(20),  
 seller_nick varchar(50)  
)  

那么分表以后,假設(shè)user_id = 257,并且auction_id = 100,需要根據(jù)auction_id來查詢對應(yīng)的訂單信息口猜,則對應(yīng)的SQL語句如下:

select * from order_1 where user_id=257 and auction_id = 100;  

其中负溪,order_1是根據(jù)257%256計(jì)算得出,表示分表之后的第一張order表济炎。

小結(jié)

水平分表川抡,能夠降低單表的數(shù)據(jù)量,一定程度上可以緩解查詢性能瓶頸须尚。但本質(zhì)上這些表還保存在同一個(gè)庫中灶芝,所以庫級別還是會有IO瓶頸生兆。所以,一般不建議采用這種做法。

二. 分庫

場景:分表能夠解決單表數(shù)據(jù)量過大帶來的查詢效率下降的問題睡雇,但是,卻無法給數(shù)據(jù)庫的并發(fā)處理能力帶來質(zhì)的提升坟乾。面對高并發(fā)的讀寫訪問啃沪,當(dāng)數(shù)據(jù)庫master
服務(wù)器無法承載寫操作壓力時(shí),不管如何擴(kuò)展slave服務(wù)器堪嫂,此時(shí)都沒有意義了偎箫。
因此,我們必須換一種思路皆串,對數(shù)據(jù)庫進(jìn)行拆分淹办,從而提高數(shù)據(jù)庫寫入能力,這就是所謂的分庫!

與分表策略相似恶复,分庫可以采用通過一個(gè)關(guān)鍵字取模的方式怜森,來對數(shù)據(jù)訪問進(jìn)行路由,如下圖所示:

Paste_Image.png

還是之前的訂單表谤牡,假設(shè)user_id 字段的值為258副硅,將原有的單庫分為256個(gè)庫,那么應(yīng)用程序?qū)?shù)據(jù)庫的訪問請求將被路由到第二個(gè)庫(258%256 = 2)拓哟。

三. 分庫分表

場景:有時(shí)數(shù)據(jù)庫可能既面臨著高并發(fā)訪問的壓力想许,又需要面對海量數(shù)據(jù)的存儲問題,這時(shí)需要對數(shù)據(jù)庫既采用分表策略,又采用分庫策略流纹,以便同時(shí)擴(kuò)展系統(tǒng)的
并發(fā)處理能力糜烹,以及提升單表的查詢性能,這就是所謂的分庫分表漱凝。

分庫分表的策略比前面的僅分庫或者僅分表的策略要更為復(fù)雜疮蹦,一種分庫分表的路由策略如下:

  1. 中間變量 = user_id % (分庫數(shù)量 * 每個(gè)庫的表數(shù)量)
  2. 庫 = 取整數(shù) (中間變量 / 每個(gè)庫的表數(shù)量)
  3. 表 = 中間變量 % 每個(gè)庫的表數(shù)量

同樣采用user_id作為路由字段,首先使用user_id 對庫數(shù)量*每個(gè)庫表的數(shù)量取模茸炒,得到一個(gè)中間變量愕乎;然后使用中間變量除以每個(gè)庫表的數(shù)量,取整壁公,便得到
對應(yīng)的庫感论;而中間變量對每個(gè)庫表的數(shù)量取模,即得到對應(yīng)的表紊册。

分庫分表策略詳細(xì)過程如下:

假設(shè)將原來的單庫單表order拆分成256個(gè)庫比肄,每個(gè)庫包含1024個(gè)表,那么按照前面所提到的路由策略囊陡,對于user_id=262145 的訪問芳绩,路由的計(jì)算過程如下:

  1. 中間變量 = 262145 % (256 * 1024) = 1
  2. 庫 = 取整 (1/1024) = 0
  3. 表 = 1 % 1024 = 1

這就意味著,對于user_id=262145 的訂單記錄的查詢和修改撞反,將被路由到第0個(gè)庫的第1個(gè)order_1表中執(zhí)行M咨!遏片!

分庫分表的難點(diǎn)

垂直分庫帶來的問題和解決思路:

跨庫join的問題

在拆分之前嘹害,系統(tǒng)中很多列表和詳情頁所需的數(shù)據(jù)是可以通過sql join來完成的。而拆分后吮便,數(shù)據(jù)庫可能是分布式在不同實(shí)例和不同的主機(jī)上吼拥,join將變得非常麻煩。而且基于架構(gòu)規(guī)范线衫,性能,安全性等方面考慮惑折,一般是禁止跨庫join的授账。那該怎么辦呢?首先要考慮下垂直分庫的設(shè)計(jì)問題惨驶,如果可以調(diào)整白热,那就優(yōu)先調(diào)整。如果無法調(diào)整的情況粗卜,下面筆者將結(jié)合以往的實(shí)際經(jīng)驗(yàn)屋确,總結(jié)幾種常見的解決思路,并分析其適用場景。

全局表

所謂全局表攻臀,就是有可能系統(tǒng)中所有模塊都可能會依賴到的一些表焕数。比較類似我們理解的“數(shù)據(jù)字典”。為了避免跨庫join查詢刨啸,我們可以將這類表在其他每個(gè)數(shù)據(jù)庫中均保存一份堡赔。同時(shí),這類數(shù)據(jù)通常也很少發(fā)生修改(甚至幾乎不會)设联,所以也不用太擔(dān)心“一致性”問題善已。

字段冗余

這是一種典型的反范式設(shè)計(jì),在互聯(lián)網(wǎng)行業(yè)中比較常見离例,通常是為了性能來避免join查詢换团。

舉個(gè)電商業(yè)務(wù)中很簡單的場景:

“訂單表”中保存“賣家Id”的同時(shí),將賣家的“Name”字段也冗余宫蛆,這樣查詢訂單詳情的時(shí)候就不需要再去查詢“賣家用戶表”艘包。

字段冗余能帶來便利,是一種“空間換時(shí)間”的體現(xiàn)洒扎。但其適用場景也比較有限辑甜,比較適合依賴字段較少的情況。最復(fù)雜的還是數(shù)據(jù)一致性問題袍冷,這點(diǎn)很難保證磷醋,可以借助數(shù)據(jù)庫中的觸發(fā)器或者在業(yè)務(wù)代碼層面去保證。當(dāng)然胡诗,也需要結(jié)合實(shí)際業(yè)務(wù)場景來看一致性的要求邓线。就像上面例子,如果賣家修改了Name之后煌恢,是否需要在訂單信息中同步更新呢骇陈?

數(shù)據(jù)同步

定時(shí)A庫中的tab_a表和B庫中tbl_b有關(guān)聯(lián),可以定時(shí)將指定的表做同步瑰抵。當(dāng)然你雌,同步本來會對數(shù)據(jù)庫帶來一定的影響,需要性能影響和數(shù)據(jù)時(shí)效性中取得一個(gè)平衡二汛。這樣來避免復(fù)雜的跨庫查詢婿崭。筆者曾經(jīng)在項(xiàng)目中是通過ETL工具來實(shí)施的。

系統(tǒng)層組裝

在系統(tǒng)層面肴颊,通過調(diào)用不同模塊的組件或者服務(wù)氓栈,獲取到數(shù)據(jù)并進(jìn)行字段拼裝。說起來很容易婿着,但實(shí)踐起來可真沒有這么簡單授瘦,尤其是數(shù)據(jù)庫設(shè)計(jì)上存在問題但又無法輕易調(diào)整的時(shí)候醋界。

具體情況通常會比較復(fù)雜。下面筆者結(jié)合以往實(shí)際經(jīng)驗(yàn)提完,并通過偽代碼方式來描述形纺。

簡單的列表查詢的情況

Paste_Image.png

偽代碼很容易理解,先獲取“我的提問列表”數(shù)據(jù)氯葬,然后再根據(jù)列表中的UserId去循環(huán)調(diào)用依賴的用戶服務(wù)獲取到用戶的RealName挡篓,拼裝結(jié)果并返回。

有經(jīng)驗(yàn)的讀者一眼就能看出上訴偽代碼存在效率問題帚称。循環(huán)調(diào)用服務(wù)官研,可能會有循環(huán)RPC,循環(huán)查詢數(shù)據(jù)庫…不推薦使用闯睹。再看看改進(jìn)后的:

Paste_Image.png

這種實(shí)現(xiàn)方式戏羽,看起來要優(yōu)雅一點(diǎn),其實(shí)就是把循環(huán)調(diào)用改成一次調(diào)用楼吃。當(dāng)然始花,用戶服務(wù)的數(shù)據(jù)庫查詢中很可能是In查詢,效率方面比上一種方式更高孩锡。(坊間流傳In查詢會全表掃描酷宵,存在性能問題,傳聞不可全信躬窜。其實(shí)查詢優(yōu)化器都是基本成本估算的浇垦,經(jīng)過測試,在In語句中條件字段有索引的時(shí)候荣挨,條件較少的情況是會走索引的男韧。這里不細(xì)展開說明,感興趣的朋友請自行測試)默垄。

垂直分庫總結(jié)和實(shí)踐建議

本篇中主要描述了幾種常見的拆分方式此虑,并著重介紹了垂直分庫帶來的一些問題和解決思路。讀者朋友可能還有些問題和疑惑口锭。

  1. 我們目前的數(shù)據(jù)庫是否需要進(jìn)行垂直分庫朦前?

根據(jù)系統(tǒng)架構(gòu)和公司實(shí)際情況來,如果你們的系統(tǒng)還是個(gè)簡單的單體應(yīng)用鹃操,并且沒有什么訪問量和數(shù)據(jù)量况既,那就別著急折騰“垂直分庫”了,否則沒有任何收益组民,也很難有好結(jié)果。

切記悲靴,“過度設(shè)計(jì)”和“過早優(yōu)化”是很多架構(gòu)師和技術(shù)人員常犯的毛病臭胜。

  1. 垂直拆分有沒有原則或者技巧莫其?

沒有什么黃金法則和標(biāo)準(zhǔn)答案。一般是參考系統(tǒng)的業(yè)務(wù)模塊拆分來進(jìn)行數(shù)據(jù)庫的拆分耸三。比如“用戶服務(wù)”乱陡,對應(yīng)的可能就是“用戶數(shù)據(jù)庫”。但是也不一定嚴(yán)格一一對應(yīng)仪壮。有些情況下憨颠,數(shù)據(jù)庫拆分的粒度可能會比系統(tǒng)拆分的粒度更粗。筆者也確實(shí)見過有些系統(tǒng)中的某些表原本應(yīng)該放A庫中的积锅,卻放在了B庫中爽彤。有些庫和表原本是可以合并的,卻單獨(dú)保存著缚陷。還有些表适篙,看起來放在A庫中也OK,放在B庫中也合理箫爷。

如何設(shè)計(jì)和權(quán)衡嚷节,這個(gè)就看實(shí)際情況和架構(gòu)師/開發(fā)人員的水平了。

  1. 上面舉例的都太簡單了虎锚,我們的后臺報(bào)表系統(tǒng)中join的表都有n個(gè)了硫痰,

分庫后該怎么查?

有很多朋友跟我提過類似的問題窜护。其實(shí)互聯(lián)網(wǎng)的業(yè)務(wù)系統(tǒng)中效斑,本來就應(yīng)該盡量避免join的,如果有多個(gè)join的柄慰,要么是設(shè)計(jì)不合理鳍悠,要么是技術(shù)選型有誤。請自行科普下OLAP和OLTP坐搔,報(bào)表類的系統(tǒng)在傳統(tǒng)BI時(shí)代都是通過OLAP數(shù)據(jù)倉庫去實(shí)現(xiàn)的(現(xiàn)在則更多是借助離線分析藏研、流式計(jì)算等手段實(shí)現(xiàn)),而不該向上面描述的那樣直接在業(yè)務(wù)庫中執(zhí)行大量join和統(tǒng)計(jì)概行。

參考

http://blog.csdn.net/winy_lm/article/details/50708493
http://www.open-open.com/lib/view/open1473820694158.html#articleHeader4

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末蠢挡,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子凳忙,更是在濱河造成了極大的恐慌业踏,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件涧卵,死亡現(xiàn)場離奇詭異勤家,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)柳恐,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進(jìn)店門伐脖,熙熙樓的掌柜王于貴愁眉苦臉地迎上來热幔,“玉大人,你說我怎么就攤上這事讼庇∫锞蓿” “怎么了?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵蠕啄,是天一觀的道長场勤。 經(jīng)常有香客問我,道長歼跟,這世上最難降的妖魔是什么和媳? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮嘹承,結(jié)果婚禮上窗价,老公的妹妹穿的比我還像新娘。我一直安慰自己叹卷,他們只是感情好撼港,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著骤竹,像睡著了一般帝牡。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上蒙揣,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天靶溜,我揣著相機(jī)與錄音,去河邊找鬼懒震。 笑死罩息,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的个扰。 我是一名探鬼主播瓷炮,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼递宅!你這毒婦竟也來了娘香?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤办龄,失蹤者是張志新(化名)和其女友劉穎烘绽,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體俐填,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡安接,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了英融。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片赫段。...
    茶點(diǎn)故事閱讀 40,040評論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡呀打,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出糯笙,到底是詐尸還是另有隱情,我是刑警寧澤撩银,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布给涕,位于F島的核電站,受9級特大地震影響额获,放射性物質(zhì)發(fā)生泄漏够庙。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一抄邀、第九天 我趴在偏房一處隱蔽的房頂上張望耘眨。 院中可真熱鬧,春花似錦境肾、人聲如沸剔难。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽偶宫。三九已至,卻和暖如春环鲤,著一層夾襖步出監(jiān)牢的瞬間纯趋,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工冷离, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留吵冒,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓西剥,卻偏偏與公主長得像痹栖,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子蔫耽,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評論 2 355

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