1. 程式人生 > >分庫分表設計基礎

分庫分表設計基礎

很多 有關 生成 select xxxx 維度 主備 出現 例如

隨著當今系統中的數據量越來越龐大,當我們設計系統時經常會關心數據庫的性能,以及數據庫是否需要做分庫分表處理。數據庫是否要分庫分表需要由業務吞吐量、數據庫品牌、數據量等多方面決定,分庫分表也還分為水平切分和垂直切分。這裏僅描述不同場景下,數據庫做水平的情況。

我理解的數據庫分庫分表本質上的目的就是一次數據庫查詢操作所涉及的數據量,通過架構設計和數據庫設計,把每一次數據庫交互涉及的數據量縮小。

1. 單一key條件下的分庫分表

單key查詢條件是最簡單的一類業務查詢,假設有user表

技術分享圖片

有業務查詢,按照id查詢用戶信息,就是單key查詢條件,對應的語句是

select * from user where id=‘xxxxx‘

當user表的數據量較小時在id列上有索引(一般是主鍵)的情況下,這條語句效率挺高;隨著業務增長系統內用戶增加後,效率會逐漸下降,不同數據庫產品的下降趨勢不一,性能開始下降的閾值也和表內數據量有關,例如MySQL理論上單表5000萬數據會出現性能急劇下降的情況,但如果是字段很多的表,在幾百萬數據的時候就會出現性能下降。

對於單key類業務的表,一般會選擇按照這個key的情況來進行水平切分,以user表為例的話 key就是id。水平切分一般有by range和by hash兩種常見方式。

  • By range

By range是指通過id的值的範圍去把數據切分到不同的表或者數據庫裏,比如說id在1~100000的數據放在user_t1表,id在100001~200000的數據放在user_t2表。

這種切分的優點:

切分簡單,軟件架構路由規則簡單;線性擴容方便,再多數據,再多加幾個表或者庫就好。

缺點也很明顯:

在id分布不均勻時,會出現某幾個表熱度很高,而其他表訪問量低的情況。

  • By hash

By hash是解決By range方式中id分布不均勻的場景的解決方案,通過對id進行哈希後的值再拆分,無論原來id分布情況如何,經過哈希後都會變成分布較為均勻的值。

優點:

切分簡單,數據分布均勻

缺點:

擴容時需要用新的哈希算法rehash一下,會引起數據遷移,需要在擴容時考慮數據如何平滑遷移。

數據平滑遷移一般可以這麽做

假設我們原來的分庫是下面這樣,通過id取2的模的方式分庫。

技術分享圖片

需要擴容時,采取通過id取4的模的方式分庫,可以先配置好應用,再中斷已有2套數據庫的主備復制的方式擴容,無數據遷移,如下圖所示。

技術分享圖片

平滑擴容後對4個庫裏的數據進行清洗,刪除不要的數據,再重新進行主備庫搭建後,完成平滑擴容。

技術分享圖片

2. 雙key條件下的分庫分表

但是實際應用中,一般不會只按一個維度進行數據訪問,按單一key方式分庫分表後,其他維度的數據訪問,就變得需要遍歷所有庫才能完成了。假設60%是通過id查詢,30%是通過name查詢,還有10%是其他維度的查詢組合。這種情況下,按id分表意味著name和其他維度的查詢需要遍歷所有的庫才能得出結果。在name和id的查詢需要兼顧的時候,通過id分庫對於name維度查詢就是無法接受的結果。

對於這種查詢,可以通過在id裏融合name信息的方式做分表來解決,假設通過id = uuid + hash(name)方式生成用戶的id列。再通過hash(id裏由name哈希來的部分)進行分庫。這樣具有相同hash值的name列也會在同一個庫裏,通過id查詢時通過uuid裏hash(name)的部分也可以定位出該id的數據位於哪個庫。

說的很抽象,舉個例子,name%8 = 3, id = uuid(63)+“3”,分庫策略為對id最後1位模2,這樣就既能保證通過id的查詢能直接定位到庫(取最後一位的數字模2),也能保證通過name的查詢能直接定位到庫(模8後再模2)。在這個例子的前提條件下,可以使id上60%的查詢和name上30%的查詢不需要遍歷全庫,且最高支持分8片(最高支持的分片數取決於name字段的哈希結果,模16就可以最多支持16分片了)。

分庫分表設計基礎