MySQL 分庫分表 方案方法

2021-10-07 07:29:18 字數 2637 閱讀 3542

眾所周知,資料庫很容易成為應用系統的瓶頸。單機資料庫的資源和處理能力有限,在高併發的分布式系統中,可採用分庫分表突破單機侷限。本文總結了分庫分表的相關概念、全域性id的生成策略、分片策略、平滑擴容方案、以及流行的方案。

在業務量不大時,單庫單錶即可支撐。

當資料量過大儲存不下、或者併發量過大負荷不起時,就要考慮分庫分表。

讀寫分離: 不同的資料庫,同步相同的資料,分別只負責資料的讀和寫;

分割槽: 指定分割槽列表示式,把記錄拆分到不同的區域中(必須是同一伺服器,可以是不同硬碟),應用看來還是同一張表,沒有變化;

分庫:乙個系統的多張資料表,儲存到多個資料庫例項中;

分表: 對於一張多行(記錄)多列(字段)的二維資料表,又分兩種情形:

(1) 垂直分表: 豎向切分,不同分表儲存不同的字段,可以把不常用或者大容量、或者不同業務的字段拆分出去;

(2) 水平分表(最複雜): 橫向切分,按照特定分片演算法,不同分表儲存不同的記錄。

1.2 真的要採用分庫分表?

需要注意的是,分庫分表會為資料庫維護和業務邏輯帶來一系列複雜性和效能損耗,除非預估的業務量大到萬不得已,切莫過度設計、過早優化。

規劃期內的資料量和效能問題,嘗試能否用下列方式解決:

當前資料量:如果沒有達到幾百萬,通常無需分庫分表;

資料量問題:增加磁碟、增加分庫(不同的業務功能表,整表拆分至不同的資料庫);

效能問題:公升級cpu/記憶體、讀寫分離、優化資料庫系統配置、優化資料表/索引、優化 sql、分割槽、資料表的垂直切分;

如果仍未能奏效,才考慮最複雜的方案:資料表的水平切分。

優點:資料庫自帶功能,有序,效能佳。

缺點:單庫單錶無妨,分庫分表時如果沒有規劃,id可能重複。解決方案:

2.1.1 設定自增偏移和步長

假設總共有 10 個分表

級別可選: session(會話級), global(全域性)

set @@session.auto_increment_offset = 1; ## 起始值, 分別取值為 1~10

set @@session.auto_increment_increment = 10; ## 步長增量

如果採用該方案,在擴容時需要遷移已有資料至新的所屬分片。

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)。

優點:簡單,全球唯一;

缺點:儲存和傳輸空間大,無序,效能欠佳。

參考資料: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 遇翻轉,則等待至下一毫秒)

根據特定字段(比如使用者id、訂單時間)的範圍,值在該區間的,劃分到特定節點。

優點:集群擴容後,指定新的範圍落在新節點即可,無需進行資料遷移。

缺點:如果按時間劃分,資料熱點分布不均(歷史數冷當前資料熱),導致節點負荷不均。

缺點:擴容後需要遷移資料。

優點:擴容後無需遷移資料。—修改 需要遷移資料

3.4 snowflake 分片

優點:擴容後無需遷移資料。

4.1 分布式事務

參見 分布式事務的解決方案

由於兩階段/三階段提交對效能損耗大,可改用事務補償機制。

4.2 跨節點 join

對於單庫 join,mysql 原生就支援;

對於多庫,出於效能考慮,不建議使用 mysql 自帶的 join,可以用以下方案避免跨節點 join:

全域性表: 一些穩定的共用資料表,在各個資料庫中都儲存乙份;

字段冗餘: 一些常用的共用字段,在各個資料表中都儲存乙份;

應用組裝:應用獲取資料後再組裝。

另外,某個 id 的使用者資訊在哪個節點,他的關聯資料(比如訂單)也在哪個節點,可以避免分布式查詢。

4.3 跨節點聚合

只能在應用程式端完成。

但對於分頁查詢,每次大量聚合後再分頁,效能欠佳。

4.4 節點擴容

節點擴容後,新的分片規則導致資料所屬分片有變,因而需要遷移資料。

Mysql分庫分表方案

1.為什麼要分表 當一張表的資料達到幾千萬時,你查詢一次所花的時間會變多,如果有聯合查詢的話,我想有可能會死在那兒了。分表的目的就在於此,減小資料庫的負擔,縮短查詢時間。mysql中有一種機制是表鎖定和行鎖定,是為了保證資料的完整性。表鎖定表示你們都不能對這張表進行操作,必須等我對錶操作完才行。行鎖...

mysql分庫分表方案

分庫分表的幾種方式 1 把乙個例項中的多個資料庫拆分到不同的例項 2 把乙個庫中的表分離到不同的資料庫中 3 對乙個庫中的相關表進行水平拆分到不同的例項資料庫中 如何選擇分割槽鍵 1 分割槽鍵要能盡量避免跨分片查詢的發生 2 分割槽鍵要能盡量使各個分片中的資料平均 如何儲存無需分片的表 1 每個分片...

MySQL分庫分表方案

不管是io瓶頸,還是cpu瓶頸,最終都會導致資料庫的活躍連線數增加,進而逼近甚至達到資料庫可承載活躍連線數的閾值。在業務service來看就是,可用資料庫連線少甚至無連線可用。接下來就可以想象了吧 併發量 吞吐量 崩潰 1 io瓶頸 第一種 磁碟讀io瓶頸,熱點資料太多,資料庫快取放不下,每次查詢時...