**:
眾所周知,資料庫很容易成為應用系統的瓶頸。單機資料庫的資源和處理能力有限,在高併發的分布式系統中,可採用分庫分表突破單機侷限。本文總結了分庫分表的相關概念、全域性id的生成策略、分片策略、平滑擴容方案、以及流行的方案。
1 分庫分表概述
在業務量不大時,單庫單錶即可支撐。
當資料量過大儲存不下、或者併發量過大負荷不起時,就要考慮分庫分表。
1.1 分庫分表相關術語
讀寫分離: 不同的資料庫,同步相同的資料,分別只負責資料的讀和寫;
分割槽: 指定分割槽列表示式,把記錄拆分到不同的區域中(必須是同一伺服器,可以是不同硬碟),應用看來還是同一張表,沒有變化;
分庫:乙個系統的多張資料表,儲存到多個資料庫例項中;
分表: 對於一張多行(記錄)多列(字段)的二維資料表,又分兩種情形:
(1) 垂直分表: 豎向切分,不同分表儲存不同的字段,可以把不常用或者大容量、或者不同業務的字段拆分出去;
(2) 水平分表(最複雜): 橫向切分,按照特定分片演算法,不同分表儲存不同的記錄。
1.2 真的要採用分庫分表?
需要注意的是,分庫分表會為資料庫維護和業務邏輯帶來一系列複雜性和效能損耗,除非預估的業務量大到萬不得已,切莫過度設計、過早優化。
規劃期內的資料量和效能問題,嘗試能否用下列方式解決:
當前資料量:如果沒有達到幾百萬,通常無需分庫分表;
資料量問題:增加磁碟、增加分庫(不同的業務功能表,整表拆分至不同的資料庫);
效能問題:公升級cpu/記憶體、讀寫分離、優化資料庫系統配置、優化資料表/索引、優化 sql、分割槽、資料表的垂直切分;
如果仍未能奏效,才考慮最複雜的方案:資料表的水平切分。
2 全域性id生成策略
2.1 自動增長列
優點:資料庫自帶功能,有序,效能佳。
缺點:單庫單錶無妨,分庫分表時如果沒有規劃,id可能重複。解決方案:
2.1.1 設定自增偏移和步長
## 假設總共有 10 個分表
## 級別可選: session(會話級), global(全域性)
set @@session.auto_increment_offset = 1; ## 起始值, 分別取值為 1~10
set @@session.auto_increment_increment = 10; ## 步長增量12
34如果採用該方案,在擴容時需要遷移已有資料至新的所屬分片。
2.1.2 全域性id對映表
在全域性 redis 中為每張資料表建立乙個 id 的鍵,記錄該錶當前最大 id;
每次申請 id 時,都自增 1 並返回給應用;
redis 要定期持久至全域性資料庫。
2.2 uuid(128位)
在一台機器上生成的數字,它保證對在同一時空中的所有機器都是唯一的。通常平台會提供生成uuid的api。
uuid 由4個連字型大小(-)將32個位元組長的字串分隔後生成的字串,總共36個位元組長。形如:550e8400-e29b-41d4-a716-446655440000。
uuid 的計算因子包括:乙太網卡位址、納秒級時間、晶元id碼和許多可能的數字。
uuid 是個標準,其實現有幾種,最常用的是微軟的 guid(globals unique identifiers)。
優點:簡單,全球唯一;
缺點:儲存和傳輸空間大,無序,效能欠佳。
2.3 comb(組合)
參考資料:the cost of guids as primary keys
組合 guid(10位元組) 和時間(6位元組),達到有序的效果,提高索引效能。
2.4 snowflake(雪花) 演算法
參考資料:twitter/snowflake,snowflake 演算法詳解
snowflake 是 twitter 開源的分布式 id 生成演算法,其結果為 long(64bit) 的數值。
其特性是各節點無需協調、按時間大致有序、且整個集群各節點單不重複。
該數值的預設組成如下(符號位之外的三部分允許個性化調整):
1bit: 符號位,總是 0(為了保證數值是正數)。
41bit: 毫秒數(可用 69 年);
10bit: 節點id(5bit資料中心 + 5bit節點id,支援 32 * 32 = 1024 個節點)
12bit: 流水號(每個節點每毫秒內支援 4096 個 id,相當於 409萬的 qps,相同時間內如 id 遇翻轉,則等待至下一毫秒)
3 分片策略
3.1 連續分片
根據特定字段(比如使用者id、訂單時間)的範圍,值在該區間的,劃分到特定節點。
優點:集群擴容後,指定新的範圍落在新節點即可,無需進行資料遷移。
缺點:如果按時間劃分,資料熱點分布不均(歷史數冷當前資料熱),導致節點負荷不均。
3.3 id取模分片
缺點:擴容後需要遷移資料。
3.2 一致性hash演算法
優點:擴容後無需遷移資料。
3.4 snowflake 分片
優點:擴容後無需遷移資料。
4 分庫分表引入的問題
4.1 分布式事務
參見 分布式事務的解決方案
由於兩階段/三階段提交對效能損耗大,可改用事務補償機制。
4.2 跨節點 join
對於單庫 join,mysql 原生就支援;
對於多庫,出於效能考慮,不建議使用 mysql 自帶的 join,可以用以下方案避免跨節點 join:
全域性表: 一些穩定的共用資料表,在各個資料庫中都儲存乙份;
字段冗餘: 一些常用的共用字段,在各個資料表中都儲存乙份;
應用組裝:應用獲取資料後再組裝。
另外,某個 id 的使用者資訊在哪個節點,他的關聯資料(比如訂單)也在哪個節點,可以避免分布式查詢。
4.3 跨節點聚合
只能在應用程式端完成。
但對於分頁查詢,每次大量聚合後再分頁,效能欠佳。
4.4 節點擴容
節點擴容後,新的分片規則導致資料所屬分片有變,因而需要遷移資料。
mysql 分庫分表分割槽 動態擴容 總結
mysql 自帶有分區分表策略 具體參考只能說單庫情況下 並且簡單的情況如按時間做range分割槽可以使用mysql自帶分割槽策略。更多的情況下完全要自己 邏輯實現。sharding jdbc和mycat使用不同的理念,sharding jdbc目前是基於jdbc驅動,無需額外的proxy,因此也無...
mysql分表分庫實現 MySql分表分庫思路
一.資料庫瓶頸 1.1io瓶頸 第一種 磁碟讀io瓶頸,熱點資料太多,資料庫快取放不下,每次查詢時會產生大量的io 分庫和垂直分表 第二種 網路io瓶頸,請求的資料太多,網路頻寬不夠 分庫 1.2cpu瓶頸 第一種 sql問題,如sql中包含join,group by,order by,非索引字段條...
MySQL範圍分表分庫 mysql 分表分庫策略
唯一id的生成 下面列舉幾種常見的唯一id生成方案,需要滿足兩大核心需求 1.全域性唯一 2趨勢有序 1.用資料庫的auto increment 自增id 來生成,每次通過寫入資料庫一條記錄,利用資料庫id自增的特性獲取唯一,有序的id。優點 使用資料庫原有的功能,相對簡單 能夠保證唯一 能夠保證遞...