淺談分布式數據庫
文章集中整理總結mysql分庫分表開源產品,分布式數據庫的設計,以及實際應用案例等相關內容,部分附上本文作者實際應用過程中的理解。
本文感謝sjdbc,mycat,姜承堯,林濤等文章提供的精彩介紹。
1、先拋出兩個問題
問題一、當mysql單表數據量爆炸時,你怎麽辦?
問題二、當你的數據庫無法承受高強度io時你怎麽辦?
2、 基本概念
2.1 談數據庫分片需要首先確定以下概念
? 1) 單庫,就是一個庫
? 2) 分片(sharding),分片解決擴展性
問題,屬於水平拆分,引入分片,就引入了數據路由
和分區鍵
的概念。分表解決的是數據量過大的問題,分庫解決的是數據庫性能瓶頸的問題。
? 3) 分組(group),分組解決可用性
問題,分組通常通過主從復制(replication
)的方式實現。(各種可用級別方案單獨介紹)
? 4) 互聯網公司數據庫實際軟件架構是(大數據量下
):又分片,又分組(如下圖)
3、 分片
3.1 水平拆分,垂直拆分都是什麽?
分區表?1)若不走分區鍵很容易出現全表鎖,並發上來後簡直是災難。2)自己分庫分表,自己掌控業務場景、訪問模式,可控。mysql分區表官方介紹是針對myisam做的優化,你知道他怎麽玩的?分半天還是一個ibdata是不是很尷尬
3.2 為什麽分表?
? 關系型數據庫在大於一定數據量的情況下檢索性能會急劇下降。在面對互聯網海量數據情況時,所有數據都存於一張表,顯然會輕易超過數據庫表可承受的數據量閥值
水平拆分如果能預估規模,越早做成本越低。
2.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路由到指定的數據庫中)
盜一波圖
? 2) 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所接收。
2) 同步復制
Master提交事務,直到事務在
所有的Slave
都已提交,此時才會返回客戶端,事務執行完畢。缺點:完成一個事務可能會有很大的延遲。
3) 半同步復制
半同步復制工作的機制處於同步和異步之間,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方案
4.3.1 MHA
4.3.2 MMM
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任務線
類型 | 任務 | 備註 | 影線系統 | 風險 |
---|---|---|---|---|
design | 海關遷移方案設計評審 | … | … | 無 |
design | 分庫分表技術選型 | jproxy | … | 無 |
apply | 申請遷移相關應用(輔助系統) | 跑批任務 | … | 無 |
apply | 申請mysql集群 | dbs系統 | … | 無 |
apply | 申請jproxy集群 | 直接找接口人 | … | 無 |
apply | 申請es集群 | esm傑斯 | … | 無 |
coding | trace表服務中心化 | soa | center | 高 |
coding | 涉及trace業務邏輯梳理,全部切換中心接口 | 接口完全適配 | platform | 低 |
verify | 回歸測試,並線上走單驗證一段時間 | 先預發後正式 | … | 高 |
coding | 實現mysql版本共2個表sql映射文件 | 基於自主研發的generator | center | 低 |
verify | mysql版本sql映射文件單元測試 | 基於自主研發的generator | center | 低 |
coding | trace表實現基於jproxy的分庫分表 | 128個庫(主) 1主3從 | center | 中 |
coding | es分別按照商家id分片,保稅區id分片,異步寫,讀開放jsf | 2套集群4套索引 | es | 中 |
coding | 中心接口加入代理層,可利用開關切換讀mongo/mysql/es | … | center | 高 |
coding | 異步補償mongo,mysql,es功能開發 | 基於jmq | platform | 中 |
coding | 代理層實現mongo和mysql版本互為主被雙寫(mongo主),異步寫es | 雙11後mysql主 | center | 高 |
verify | 線上開雙寫(包括es) | 兩套es集群 | … | 中 |
coding | 倒庫功能開發,數據校驗功能開發 | reactor | config | 高 |
verify | 倒庫,並進行數據校驗 | 校驗規則(特殊字段不校驗) | … | 高 |
verify | 對中心接口進行壓測 | 線上,壓測環境隔離(jsf別名) | … | 高 |
coding | 優化配置(mysql調整最大連接數,es使用filterCache) | … | … | 高 |
verify | 對中心接口進行壓測 | … | … | 高 |
verify | 升級後架構正式上線 | … | … | 無 |
verify | 監控切換mysql之後的接口性能 | … | … | 無 |
verify | 監控切換mysql之後對相關依賴系統的影響 | … | … | 無 |
todo | 停mongo寫 | … | … | 無 |
todo | 繼續遷移海關mongo中其他表(以上均為trace表) | … | … | 無 |
todo | 徹底下線mongo數據庫服務器,只保留mysql服務器 | … | … | 無 |
5.2 記錄一次異構具有復雜分片規則數據庫的過程
5.2.1 難點
? 交易庫存復雜的分片規則,數據量大,更新頻繁,一致性保證。
回到本源,緩存+隊列
5.2.2 不跑題,我們就說分片部分,如何接手一個復雜分片規則的數據庫?
參考案例如何異構一個數十億級別的數據庫
有多復雜?? 6000+表,28個庫,4套分片規則。(解決方案 sharding-jdbc)
淺談分布式數據庫