一、什么是數(shù)據(jù)切分
"Shard" 這個詞英文的意思是"碎片",而作為數(shù)據(jù)庫相關(guān)的技術(shù)用語,似乎最早見于大型多人在線角色扮演游戲中。"Sharding" 姑且稱之為"分片"。Sharding 不是一個某個特定數(shù)據(jù)庫軟件附屬的功能,而是在具體技術(shù)細(xì)節(jié)之上的抽象處理,是水平擴展(Scale Out,亦或橫向擴展、向外擴展)的解決方案,其主要目的是為突破單節(jié)點數(shù)據(jù)庫服務(wù)器的 I/O 能力限制,解決數(shù)據(jù)庫擴展性問題。通過一系列的切分規(guī)則將數(shù)據(jù)水平分布到不同的DB或table中,在通過相應(yīng)的DB路由或者table路由規(guī)則找到需要查詢的具體的DB或者table,以進(jìn)行Query操作?!皊harding”通常是指“水平切分”,這也是本文討論的重點。接下來舉個簡單的例子:
article_id(int) , title(varchar(128)),content(varchar(1024)),user_id(int)
接下來要解決的問題就是怎樣找到具體的數(shù)據(jù)庫呢?其實問題也是簡單明顯的,既然分庫的時候我們用到了區(qū)分字段user_id,那么很自然,數(shù)據(jù)庫路由的過程當(dāng)然還是少不了user_id的。就是我們知道了這個blog的user_id,就利用這個user_id,利用分庫時候的規(guī)則,反過來定位具體的數(shù)據(jù)庫。比如user_id是234,利用剛才的規(guī)則,就應(yīng)該定位到DB1,假如user_id是12343,利用該才的規(guī)則,就應(yīng)該定位到DB2。以此類推,利用分庫的規(guī)則,反向的路由到具體的DB,這個過程我們稱之為“DB路由”。
平常我們會自覺的按照范式來設(shè)計我們的數(shù)據(jù)庫,考慮到數(shù)據(jù)切分的DB設(shè)計,將違背這個通常的規(guī)矩和約束。為了切分,我們不得不在數(shù)據(jù)庫的表中出現(xiàn)冗余字段,用作區(qū)分字段或者叫做分庫的標(biāo)記字段。比如上面的article的例子中的user_id這樣的字段(當(dāng)然,剛才的例子并沒有很好的體現(xiàn)出user_id的冗余性,因為user_id這個字段即使就是不分庫,也是要出現(xiàn)的,算是我們撿了便宜吧)。
二、如何做到數(shù)據(jù)切分
1.物理上
對數(shù)據(jù)通過一系列的切分規(guī)則將數(shù)據(jù)分布到不同的DB服務(wù)器上,通過路由規(guī)則路由訪問特定的數(shù)據(jù)庫,這樣一來每次訪問面對的就不是單臺服務(wù)器了,而是N臺服務(wù)器,這樣就可以降低單臺機器的負(fù)載壓力。
2.數(shù)據(jù)庫內(nèi)
對數(shù)據(jù)通過一系列的切分規(guī)則,將數(shù)據(jù)分布到一個數(shù)據(jù)庫的不同表中,比如將article分為article_001,article_002等子表,若干個子表水平拼合有組成了邏輯上一個完整的article表,這樣做的目的其實也是很簡單的。舉個例子說明,比如article表中現(xiàn)在有5000w條數(shù)據(jù),此時我們需要在這個表中增加(insert)一條新的數(shù)據(jù),insert完畢后,數(shù)據(jù)庫會針對這張表重新建立索引,5000w行數(shù)據(jù)建立索引的系統(tǒng)開銷還是不容忽視的。但是反過來,假如我們將這個表分成100個table呢,從article_001一直到article_100,5000w行數(shù)據(jù)平均下來,每個子表里邊就只有50萬行數(shù)據(jù),這時候我們向一張只有50w行數(shù)據(jù)的table中insert數(shù)據(jù)后建立索引的時間就會呈數(shù)量級的下降,極大了提高了DB的運行時效率,提高了DB的并發(fā)量。當(dāng)然分表的好處還不知這些,還有諸如寫操作的鎖操作等,都會帶來很多顯然的好處。
3.綜上
分庫降低了單點機器的負(fù)載;分表,提高了數(shù)據(jù)操作的效率,尤其是Write操作的效率。