分庫與分表設計

一、數據的切分模式

  垂直(縱向)切分:把單一的表拆分成多個表,並分散到不同的數據庫(主機)上。

  水平(橫向)切分:根據表中數據的邏輯關係,將同一個表中的數據按照某種條件拆分到多臺數據庫(主機)上。

  ①、垂直切分

        一個數據庫由多個表構成,每個表對應不同的業務,垂直切分是指按照業務將表進行分類,將其分佈到不同的數據庫上,這樣就將數據分擔到了不同的庫上(專庫專用)。

優點如下:

1)、拆分後業務清晰,拆分規則明確。

2)、系統之間進行整合或擴展很容易。

3)、按照成本、應用的等級、應用的類型等將表放到不同的機器上,便於管理。

4)、便於實現動靜分離、冷熱分離的數據庫表的設計模式。

5)、數據維護簡單。

缺點如下:

1)、部分業務表無法關聯(Join),只能通過接口方式解決,提高了系統的複雜度。

2)、受每種業務的不同限制,存在單庫性能瓶頸,不易進行數據擴展和提升性能。

3)、事務處理複雜。

②、水平切分

     與垂直切分對比,水平切分不是將表進行分類,而是將其按照某個字段的某種規則分散到多個庫中,在每個表中包含一部分數據,所有表加起來就是全量的數據。

簡單來說,我們可以將對數據的水平切分理解爲按照數據行進行切分,就是將表中的某些行切分到一個數據庫表中,而將其他行切分到其他數據庫表中。

這種切分方式根據單表的數據量的規模來切分,保證單表的容量不會太大,從而保證了單表的查詢等處理能力,例如將用戶的信息表拆分成User1、User2等,表結構是完全一樣的。我們通常根據某些特定的規則來劃分表,比如根據用戶的ID來取模劃分。

優點如下:

1)、單庫單表的數據保持在一定的量級,有助於性能的提高。

2)、切分的表的結構相同,應用層改造較少,只需要增加路由規則即可。

3)、提高了系統的穩定性和負載能力。

缺點如下:

1)、切分後,數據是分散的,很難利用數據庫的Join操作,跨庫Join性能較差。

2)、拆分規則難以抽象。

3)、分片事務的一致性難以解決。

4)、數據擴容的難度和維護量極大。

③、 水平切分的分片維度

對數據切片有不同的切片維度,可以參考Mycat提供的切片方式(見本書3.4節),這裏只介紹兩種最常用的切片維度。

1)按照哈希切片

   對數據的某個字段求哈希,再除以分片總數後取模,取模後相同的數據爲一個分片,這樣的將數據分成多個分片的方法叫作哈希分片。

2)按照時間切片

   與按照哈希切片不同,這種方式是按照時間的範圍將數據分佈到不同的分片上的,例如,我們可以將交易數據按照月進行切片,或者按照季度進行切片,由交易數據的多少來決定按照什麼樣的時間週期對數據進行切片。

④、垂直切分和水平切分的共同點:

       存在分佈式事務的問題。

       存在跨節點Join的問題。

       存在跨節點合併排序、分頁的問題。

       存在多數據源管理的問題。

二、分庫與分錶帶來的分佈式困境與應對之策

數據遷移與擴容問題

前面介紹到水平分表策略歸納總結爲隨機分表和連續分表兩種情況。連續分表有可能存在數據熱點的問題,有些表可能會被頻繁地查詢從而造成較大壓力,熱數據的表就成爲了整個庫的瓶頸,而有些表可能存的是歷史數據,很少需要被查詢到。連續分表的另外一個好處在於比較容易,不需要考慮遷移舊的數據,只需要添加分表就可以自動擴容。隨機分表的數據相對比較均勻,不容易出現熱點和併發訪問的瓶頸。但是,分表擴展需要遷移舊的數據
針對於水平分表的設計至關重要,需要評估中短期內業務的增長速度,對當前的數據量進行容量規劃,綜合成本因素,推算出大概需要多少分片。對於數據遷移的問題,一般做法是
通過程序先讀出數據,然後按照指定的分表策略再將數據寫入到各個分表中。

表關聯問題

在單庫單表的情況下,聯合查詢是非常容易的。但是,隨着分庫與分表的演變,聯合查詢就遇到跨庫關聯和跨表關係問題。在設計之初就應該儘量避免聯合查詢,可以通過程序中進行拼裝,或者通過反範式化設計進行規避。

分頁與排序問題

一般情況下,列表分頁時需要按照指定字段進行排序。在單庫單表的情況下,分頁和排序也是非常容易的。但是,隨着分庫與分表的演變,也會遇到跨庫排序和跨表排序問題。爲了最終結果的準確性,需要在不同的分表中將數據進行排序並返回,並將不同分表返回的結果集進行彙總和再次排序,最後再返回給用戶。

方法一:全局視野法

1)將order by time offset X limit Y,改寫成order by time offset 0 limit X+Y

2)服務層對得到的N*(X+Y)條數據進行內存排序,內存排序後再取偏移量X後的Y條記錄

這種方法隨着翻頁的進行,性能越來越低

方法二:業務折衷法-禁止跳頁查詢

1)用正常的方法取得第一頁數據,並得到第一頁記錄的time_max

2)每次翻頁,將order by time offset X limit Y,改寫成order by time where time>$time_max limit Y

以保證每次只返回一頁數據,性能爲常量

方法三:二次查詢法

1)將order by time offset X limit Y,改寫成order by time offset X/N limit Y

2)找到最小值time_min

3between二次查詢,order by time between $time_min and $time_i_max

4)設置虛擬time_min,找到time_min在各個分庫的offset,從而得到time_min在全局的offset

5)得到了time_min在全局的offset,自然得到了全局的offset X limit Y

分佈式事務問題

隨着分庫與分表的演變,一定會遇到分佈式事務問題,那麼如何保證數據的一致性就成爲一個必須面對的問題。目前,分佈式事務並沒有很好的解決方案,難以滿足數據強一致性,一般情況下,使存儲數據儘可能達到用戶一致,保證系統經過一段較短的時間的自我恢復和修正,數據最終達到一致

分佈式全局唯一ID

在單庫單表的情況下,直接使用數據庫自增特性來生成主鍵ID,這樣確實比較簡單。在分庫分表的環境中,數據分佈在不同的分表上,不能再借助數據庫自增長特性。需要使用全局唯一 ID,例如 UUID、GUID等。關於如何選擇合適的全局唯一 ID,我會在後面的章節中進行介紹。

業界方案:

UUID:通過唯一識別碼16個字節128位的長數字。

組成部分:當前日期和時間序列+全局的唯一性網卡mac地址

優點:代碼實現簡單、不佔用寬帶、數據遷移不受影響

缺點:無序、無法保證趨勢遞增(要求3)字符存儲、傳輸、查詢慢、不可讀

Snowflake雪花算法

 國外的twitter分佈式下ID生成算法

1bit+41bit+10bit+10+bit=62bit

高位隨機+毫秒數+機器碼(數據中心+機器id)+10的流水好

國內:

保證數據的唯一性就行了IDC機房

優點:代碼實現簡單、不佔用寬帶、數據遷移不受影響、低位趨勢遞增

缺點:強以來時鐘(多臺服務器時間一定要一樣)、無序無法保證趨勢遞增Redis:
縮減版本、有關業務代碼沒有包含到裏頭、redis方案
優點:不依賴數據、靈活方便、性能優於數據庫的、沒有單點故障(高可用)
缺點:需要佔用網絡資源、性能要比本地生成慢、需要增加插件

三、總結

分庫與分表主要用於應對當前互聯網常見的兩個場景:海量數據和高併發。然而,分庫與分表是一把雙刃劍,雖然很好的應對海量數據和高併發對數據庫的衝擊和壓力,但是卻提高的系統的複雜度和維護成本。

因此,我的建議:需要結合實際需求,不宜過度設計,在項目一開始不採用分庫與分表設計,而是隨着業務的增長,在無法繼續優化的情況下,再考慮分庫與分表提高系統的性能。

發佈了38 篇原創文章 · 獲贊 16 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章