史上最詳盡的 MySQL 分庫分表文章

文章集中整理總結 mysql 分庫分表開源產品,分佈式數據庫的設計,以及實際應用案例等相關內容,部分附上本文作者實際應用過程中的理解。

本文感謝 sjdbc,mycat,姜承堯,林濤 等文章提供的精彩介紹。

1、先拋出兩個問題

問題一、當 mysql 單表數據量爆炸時,你怎麼辦?

問題二、當你的數據庫無法承受高強度 io 時你怎麼辦?

2、 基本概念

2.1 談數據庫分片需要首先確定以下概念

  1. 單庫, 就是一個庫

  1. 分片 (sharding),分片解決擴展性問題,屬於水平拆分,引入分片,就引入了數據路由分區鍵的概念。分表解決的是數據量過大的問題,分庫解決的是數據庫性能瓶頸的問題。

  1. 分組 (group),分組解決可用性問題,分組通常通過主從複製 (replication) 的方式實現。(各種可用級別方案單獨介紹)

  1. 互聯網公司數據庫實際軟件架構是 (大數據量下):又分片,又分組(如下圖)

3、 分片

3.1 水平拆分,垂直拆分都是什麼?

分區表?1) 若不走分區鍵很容易出現全表鎖,併發上來後簡直是災難。2) 自己分庫分表,自己掌控業務場景、訪問模式,可控。mysql 分區表官方介紹是針對 myisam 做的優化,你知道他怎麼玩的?分半天還是一個 ibdata 是不是很尷尬

3.2 爲什麼分表?

關係型數據庫在大於一定數據量的情況下檢索性能會急劇下降。在面對互聯網海量數據情況時,所有數據都存於一張表,顯然會輕易超過數據庫表可承受的數據量閥值。這個單表可承受的數據量閥值,需根據數據庫和併發量的差異,通過實際測試獲得。

水平拆分如果能預估規模,越早做成本越低。

3.3 爲什麼分庫?

單純的分表雖然可以解決數據量過大導致檢索變慢的問題,但無法解決過多併發請求訪問同一個庫,導致數據庫響應變慢的問題。所以通常水平拆分都至少要採用分庫的方式,用於一併解決大數據量和高併發的問題。這也是部分開源的分片數據庫中間件只支持分庫的原因。

3.4 分佈式事務?

但分表也有不可替代的適用場景。最常見的分表需求是事務問題。同在一個庫則不需考慮分佈式事務,善於使用同庫不同表可有效避免分佈式事務帶來的麻煩。目前強一致性的分佈式事務由於性能問題,導致使用起來並不一定比不分庫分錶快。目前採用最終一致性的柔性事務居多。分表的另一個存在的理由是,過多的數據庫實例不利於運維管理。

mysql 本身?消息補償?2PC?

3.5 小結

綜上所述,最佳實踐是合理地配合使用分庫 + 分表。

3.6 如何自己實現分庫分表?

  1. dao 層,首先通過分區鍵算出庫名錶名(如 shardKey%shardNum 算出來表 index 如 y,然後 y/(shardNum/sourceNum)=x,y 是表下標,x 是庫下標)。

  2. 把source從spring容器中拿出來,把表名當參數傳進去,拼成分片後的 sql。

  3. 思路大概是 (select … from order where … -> 先拿到 db_x 的 source 然後 select … from order_y where …)

你想這麼幹?你已經成功了。當然淘寶和噹噹的架構師也是這麼幹的。

3.7 SO,不需要我們親自動手,其實你需要做的只是按照實際需求挑選而已。

3.8 重點介紹兩個產品,先不說具體配置,只說思想

  1. sharding-jdbc(所處位置,通用數據訪問層,部署在客戶端的 jar 包,用於將用戶的 SQL 路由到指定的數據庫中)

盜一波圖

  1. jproxy

jproxy 是什麼?

jproxy 提供 MariaDB, MySQL 等數據庫的統一接入訪問,擁有流量過載保護,數據自動拆分,可配置路由規則,數據無縫遷移等功能。應用場景:數據需要分庫分表,自動擴容的應用。

爲什麼分片都是 2 的 n 次方?a % (2^n) 等價於 a & (2^n - 1) 其中一個原因就是位運算

擴容?虛擬桶。極限就是一片一庫。

演變過程 cobar->mycat->jproxy

mycat 是什麼?

簡單的說,就是:一個徹底開源的,面向企業應用開發的 “大數據庫集羣”。支持事務、ACID、可以替代 Mysql 的加強版數據庫,一個的數據庫中間件產品。

  1. 基於阿里開源的 Cobar 產品而研發,Cobar 的穩定性、可靠性、優秀的架構和性能

  2. 擁有衆多成熟的使用案例

  3. 強大的團隊 (其參與者都是 5 年以上資深軟件工程師、架構師、DBA 等)

  4. 開源,創新,持續更新

盜一波圖

4、 分組

4.1 爲什麼分組?

分組解決可用性問題

mysql 的 ha 網洛上的都是 vip 漂移實現的

方案一:MYSQL 主從複製(單活)

方案二:雙主(單活),failover 比單主簡單

方案三:雙主配 SAN 存儲(單活)

方案四:DRBD 雙主配 DRBD (單活)

方案五:NDB CLUSTER

共享存儲? 不需要複製了 更高的一致性

真正的高併發場景,什麼架構都抗不住,老老實實用緩存。

需要大量讀的場景儘量做到最終一致性。

4.2 同步,異步,半同步

  1. 異步複製 (mysql 默認)

Master 將事件寫入 binlog,但並不知道 Slave 是否或何時已經接收且已處理。當 Slave 準備好纔會向 Master 請求 binlog。缺點:不能保證一些事件都能夠被所有的 Slave 所接收。

  1. 同步複製

Master 提交事務,直到事務在所有的Slave都已提交,此時纔會返回客戶端,事務執行完畢。缺點:完成一個事務可能會有很大的延遲。

  1. 半同步複製

半同步複製工作的機制處於同步和異步之間,Master 的事務提交阻塞,只要一個Slave已收到該事務的事件且已記錄。它不會等待所有的 Slave 都告知已收到,且它只是接收,並不用等其完全執行且提交。

半同步複製的步驟:

i. 當 Slave 主機連接到 Master 時,能夠查看其是否處於半同步複製的機制。

ii. 當 Master 上開啓半同步複製的功能時,至少應該有一個 Slave 開啓其功能。此時,一個線程在 Master 上提交事務將受到阻塞,直到得知一個已開啓半同步複製功能的 Slave 已收到此事務的所有事件,或等待超時。

iii. 當一個事務的事件都已寫入其 relay-log 中且已刷新到磁盤上,Slave 纔會告知已收到。

iv. 如果等待超時,也就是 Master 沒被告知已收到,此時 Master 會自動轉換爲異步複製的機制。當至少一個半同步的 Slave 趕上了,Master 與其 Slave 自動轉換爲半同步複製的機制。

v. 半同步複製的功能要在 Master,Slave 都開啓,半同步複製纔會起作用;否則,只開啓一邊,它依然爲異步複製。

4.3 ha 方案

5、 應用案例

5.1 記錄一次 mongo 遷移 mysql 的過程 (分庫分表使用 jproxy)

mongo 怎麼了?跟分片無關的部分簡單說。

mongo 很好,只是業界並沒有成熟的 MongoDB 運維經驗,jd too。像高併發的系統 訂單和庫存 商品 還是拿 nosql 把,高併發的寫, 也不會打掛他, 比如 hbase,頂多 GC 頻繁點,但是也是可用的。一致性完全可以 CAS 搞定,而不是 mysql 的排他鎖。

  1. 中心化 (統一入口)

  2. 雙寫 (先同步寫 mysql 如果發生異常改異步,儘量避免服務不可用)

  3. 倒庫 (jproxy 支持通過遊標形式全量遍歷庫 - 逐個表操作,可以利用其異步同步數據)

  4. 數據校驗

  5. 切庫提供服務

去 mongo + 優化方案 (此處引入了分片的概念)

壓測與性能

去 mongo 任務線

TVKTll TYmIJD

5.2 記錄一次異構具有複雜分片規則數據庫的過程

5.2.1 難點

交易庫存複雜的分片規則,數據量大,更新頻繁,一致性保證。

回到本源,緩存 + 隊列

圖 kucuntouminghua

5.2.2 不跑題,我們就說分片部分,如何接手一個複雜分片規則的數據庫?

參考案例如何異構一個數十億級別的數據庫

有多複雜? 6000 + 表,28 個庫,4 套分片規則。(解決方案 sharding-jdbc)

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/6JE8UHTLbt_dMt1M4svVEw