數據庫分表分庫及分表分庫帶來的問題

相關內容:數據庫分區:MySQL分區

一、分表

數據庫分表可以解決單表海量數據的查詢性能問題。
分表分爲垂直分表和水平分表。

1、垂直分表

垂直分表一般是分割比較大的字段或者訪問頻率低的字段,將這部分字段數據剖分出來作爲一張表。簡單來說,就是把大的和不常用的與常用的分離開。
舉個例子:(1)假設一個博客網站,其文章表table_artical(id,user_id,title,abstract,content,create_time),顯然content字段對應的數據很長,當只需要查詢文章列表時,content將會大大影響table_artical的讀取速度,如果將content字段再劃分爲一個表,table_artical_detail(article_id,content),原表變爲table_artical(id,user_id,title,abstract, create_time),此時再去查詢文章列表就無需訪問content字段,如果想獲取文章詳情,通過article_id去table_articals_detail查詢即可。
在這裏插入圖片描述
(2)常用的訂單表table_order,經常還有一張訂單詳情表table_order_detail,就是將order不常用的字段分離出去。

優點:(1)能夠使行數據變小,在查詢時減少I/O的次數;
(2)能夠簡化表的結構易於維護。
缺點:(1)主鍵出現冗餘,需要管理冗餘列;
(2)查詢所有數據需要JOIN操作;
(3)會讓事務變得更加複雜。

2、水平分表

水平分表是將數據表按行進行劃分,一般表超過500W行或者10GB或者通過垂直分表後,表格依然很大時,就需要對錶進行水平分表,水平分表後要保證各表的數據量相當。
在這裏插入圖片描述

分割標準:

(1)一般採取的分表策略是對id取模,若不是整數,也可經過hash計算取整後取模。
(2)用戶表也可以根據用戶手機號進行分表,比如user138、user150、user155等,每個號碼段作爲一張表;或者其他具有明顯劃分的依據,比如學號,student2018、student2019、student2020等。
(3)對於訂單表這類表,可以採用時間進行水平分表。

優點:(1)支持非常大的數據量存儲;
(2)應用程序端整體架構改動相對較少。
缺點:(1)分片事務難以解決,跨界點Join性能較差,邏輯複雜;
(2)水平拆分會給應用增加複雜度,它通常在查詢是需要多個表名,查詢所有數據需要union操作;對於表的統計信息,可以通過增加一張表來存儲這些統計信息進行解決。
(3)如果數據持續增長,達到現有分表的瓶頸,需要增加分表,此時會出現數據重新排列的情況;這就需要分析數據增長速度,提前計算出未來某段時間需要用到分表的個數。

水平分表在插入數據時,只需要計算出該條數據所在那張數據表,比如根據id%3計算,得到1,則在業務中將table拼接成user1即可。

二、分庫

分庫可以解決單臺數據庫的併發訪問壓力問題,每個物理數據庫支持數據都是有限的,每一次的數據庫請求都會產生一次數據庫鏈接,當一個庫無法支持更多訪問的時候,我們會把原來的單個數據庫分成多個,幫助分擔壓力。

1、縱向分庫

縱向分庫就是根據業務耦合性,將關聯度低的不同表存儲在不同的數據庫,做法與大系統拆分爲多個小系統類似,按業務分類進行獨立劃分。
在這裏插入圖片描述

2、橫向分庫

當一個應用難以再細粒度的縱向分庫,或切分後數據量行數巨大,存在單庫讀寫、存儲性能瓶頸,這時候就需要進行橫向分庫了。
相對於水平分表,顯然橫向分庫後,表格也被水平切分,但是每個表放在不同的數據庫。
在這裏插入圖片描述

三、分庫分錶帶來的問題及解決

1、事務一致性問題

(1)分佈式事務
當更新內容同時分佈在不同庫中,不可避免會帶來跨庫事務問題。沒有簡單的方案,一般可使用“XA協議”和“兩階段提交”處理。
分佈式事務能夠最大限度地保證數據庫操作地原子性,但是提交事務時需要協調多個節點,推後了提交事務的時間點,延長了事務的執行時間。導致事務在訪問共享資源時發生衝突或死鎖的概率增高。
(2)最終一致性
對於性能要求很高,但對一致性要求不高的系統,只要在允許的時間段內達到最終一致性即可,可採用事務補償的方式。與事務在執行中發生錯誤後立即回滾的方式不同,事務補償是一種事後檢查補救的措施,一些常見的實現方法有:對數據進行對賬檢查,基於日誌進行對比,定期同標準數據來源進行同步等等。事務補償還要結合業務系統來考慮。

2、跨節點關聯查詢問題

單表單庫時,不同分庫分表之間的關聯查詢通過JOIN操作就可以簡單解決。但是切分之後在使用JOIN帶來的問題就很麻煩。解決此問題的方法有以下幾種:
(1)全局表
就是將業務的基礎數據或者說是所有模塊都可能依賴的一些表,在每個數據庫都保存一份,這些數據很少會修改,因此也不需要擔心一致性的問題。
(2)字段冗餘
這是一種反範式設計,利用空間換時間,比如訂單表在存儲user_id的時候將user_name也冗餘保存一遍,這樣查詢訂單詳情時,就不需要再去查詢用戶user表了。
這種方法比較適用於依賴字段比較少的情況,而且冗餘字段的數據一致性比較難保證,比如user表的user_name修改後,是否需要在歷史訂單裏更新用戶的user_name。
(3)數據組裝
分兩次查詢,第一次先查出關聯數據id,第二次根據id查詢出關聯數據,然後將獲得的數據進行字段拼裝。
(4)ER分片
關係型數據庫中,如果能夠確定好表與表之間的關係,可以將有關聯關係的數據放在同一個分片上。

3、跨節點分頁、排序、函數問題

在單庫單表的情況下,分頁和排序也是非常容易的。但是,隨着分庫與分表的演變,也會遇到跨庫排序和跨表排序問題。爲了最終結果的準確性,需要在不同的分庫分表中將數據進行排序並返回,並將不同分庫分表返回的結果集進行彙總和再次排序,最後再返回給用戶。
對於MAX、MIN、SUM、COUNT等函數操作,同樣需要對不同分庫分表進行計算後,在彙總進行計算,最後返回。

4、全局主鍵避重問題

分庫分表中,主鍵自增長無法適用,不同分庫分表中也無法保證自生成的ID全局唯一。
(1)UUID
UUID指在一臺機器上生成的數字,它保證對在同一時空中的所有機器都是唯一的,其標準形式包含32個16進制數。
該方法最簡單,本地生成,性能高,沒有網絡耗時;但是缺點也很明顯,UUID很長,佔空間大,另外其無序性會引起數據頻繁變動,導致分頁。
(2)結合數據庫維護主鍵ID表

DROP TABLE IF EXISTS sequence;
CREATE TABLE sequence (
  id bigint(20) unsigned NOT NULL auto_increment,
  stub char(1) NOT NULL default '',
  PRIMARY KEY (id),
  UNIQUE KEY UK_stub (stub)
) ENGINE=MyISAM;

stub設置爲唯一索引,則同一stub值在sequence表中只能有一條記錄,可以同時爲多張表生成全局ID。
當需要全局唯一ID時,

REPLACE INTO sequence (stub) VALUES ('a');
SELECT LAST_INSERT_ID();

這兩條語句是Connection級別的,select last_insert_id()必須與replace into在同一數據庫連接下才能得到剛剛插入的新ID。
該方法加強版可參考flickr團隊使用的一種主鍵生成策略
(3)Snowflake分佈式自增ID算法
生成64位的Long型數字,組成部分:
第一位未使用
接下來41位是毫秒級時間,41位的長度可以表示69年的時間
5位datacenterId,5位workerId。10位的長度最多支持部署1024個節點
最後12位是毫秒內的計數,12位的計數順序號支持每個節點每毫秒產生4096個ID序列
好處:毫秒數在高位,生成ID整體上按時間趨勢遞增,不依賴第三方系統,穩定性和效率較高。不足在於強烈依賴機器時鐘,如果時鐘回撥,可能導致ID重複。
(4)Leaf——美團點評分佈式ID生成系統
Leaf鏈接
業界較爲成熟解法,考慮到了高可用、容災、分佈式下時鐘等問題。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章