1、分庫分表的分類
- 垂直劃分——分庫,根據業務類型將不同的表,分到不同的數據庫,主要用來解決單點數據庫節點的壓力瓶頸問題
- 水平劃分——單數據庫節點的分表,通過不同的表名來存儲部分數據,用來解決單表數據量太大的問題。
- 水平劃分——借用中間件,水平復制相同的數據庫定義到多個實例節點,由中間件來實現分片邏輯
2、分片規則以及實現方式
分片之後,原生的SQL操作語義總是會弱化的,但是可喜的是,不同的業務場景下,對原生的SQL操作的語義弱化是能接受的,因此損失部分功能語義而提出的多樣化分片規則,分別適合不同的業務場景,需要我們深入理解然後才能做到根據不同的業務場景進行合適的選擇。
2.1、分片規則制訂思考
- 分片數據如何插入。把數據識別出來,然後執行一下分片函數即可定位到節點,再執行對應的SQL即可。
- 分片數據如何關聯查詢。最難也是主要思考的地方,因爲數據分佈不同的節點,要全表關聯是不容易實現的。
- 分片數據刪除。把查詢條件識別出來,然後執行一下分片函數即可定位到節點,再執行對應的SQL即可,對了提高執行效率,儘量避免join操作。
- 分片數據修改。把查詢條件識別出來,然後執行一下分片函數即可定位到節點,再執行對應的SQL即可,對了提高執行效率,儘量避免join操作。
2.2、分片規則
- Mycat全局表 對於一些數據量不是特別大,insert/update操作又比較少的表,直接選擇在所有的節點存儲一份相同的數據。join操作是比較方便的。
- ER分片表 對於有強關聯需求的主從表,分片之後,將會關聯的數據放在一個節點,從而實現方便的join操作。
- 多對多關聯 對於訂單表來說,可能會基於商戶會員查詢,也可能會基於商戶查詢,但同時基於二者的分片是做不到的,所以只能基於業務場景選擇是更傾向於哪一個關係,被選中的關係只需要查詢單節點,未選擇的關係查詢需要查詢所有相關的節點然後合成。
2.3、分片字段選取條件思考
- 儘可能將數據均勻的分佈到各個節點
- 該業務字段是最頻繁的或者最重要的查詢條件
- 儘量避免跨庫join操作是最重要的一條原則
2.4、分片規則算法配置
- 分片枚舉。枚舉出所有的節點,分片函數必須返回枚舉的值,否則就會報錯。
- 固定分片HASH算法。 類似於十進制的取模運算,但又不同,是取二進制的前10位,然後根據配置來運算得到節點。count:2,1 length:256,521,就是指前兩個節點256/1024=25%,後一個節點521/1024=50%。這樣的配置是把不同的區段值映射到不同的庫節點中。相比十進制取模分片,事務處理相對比較容易,因爲同一分段裏的數據往往存儲在一個節點,需要協調的事務節點較少。
- 範圍約定。在配置文件中指定不同範圍的值,存儲到不同的節點。需要預先規劃數據存儲,適合範圍一定,並且不同範圍內值比較好預測的情況。
- 取模。比如有4個節點,直接對4取模,求值是多少,就存儲到哪個節點。但是因爲同一批插入或者更新的數據,因爲id在不同的節點依次分佈,事務協調難度增大很多。
- 按日期(天)。以指定日期爲起點,每N天放入一個節點,到達結束日期,又循環這個過程。
- 取模範圍約束。是取模和範圍約定的結合,只是先取模,再根據範圍約定,放到不同的節點。
- 截取數字做hash求模範圍約束。與取模範圍約束類似,此規則支持數據符號字母取模。取prefixLenght位列所有ASCII碼的和進行求模。
- 應用決定。由應用自主決定路由到哪個分片。比如, id=05-100000002,可以配置成前兩位數字,即05就是要路由的分片。
- 截取數字hash解析截取字符串中的int數值hash分片
- 一致性hash解釋暫缺
- 按單月小時拆分單月內按照小時拆分,最小粒度是小時,可以一天最多24個分片,最少一個分片,一個月後下月從頭開始循環,每個月月尾,需要手工清理數據。
- 範圍求模分片先進行範圍分片計算得出分片組,然後組內再求模以確認最終插入的節點。
- 日期範圍hash分片思想與範圍求模一致,當由於日期在取模時會有數據集中的問題,所以改成hash方法。
- 冷熱數據分片
- 自然月分片
3、分別如何實現常見的SQL語句
要將單個數據庫操作的SQL語句實現到數據庫集羣,每個操作都是需要深入思考實現的,爲了實現類似的功能,必然會損失或者弱化部分SQL的原先語義或者效率。
join操作
這是實現起來最不容易的部分,跟分片規則有非常直接的關係,或者乾脆說,考慮分片的時候,主要就是在考慮如何實現關聯查詢操作,其它操作實現起來都是比較簡單的。只要分片規則一確定,並且沒有join操作,插入/刪除/更新就可以非常容易定位到相關節點,然後執行操作。
- 全局表 穩定不經常變的數據,在每個需要的數據節點都存有數據
- ER join join操作上可能存在關係的數據,存在一個數據節點上
- Share join 目前只支持2個表的Join操作,沒有很理解它的原理:拆分成單表的SQL語句執行,然後把各個節點的數據彙總
- catlet(人工智能) 把所有表數據查詢出來,然後在mycat這一層進行Join操作
- 未來擴展用spark/storm來進行Join操作
4、全局序列號
4.1、爲什麼要有全局序列號
在實現分庫的情況下,數據庫自增主鍵已無法保證自增主鍵的全局唯一。
4.2、如何實現?
- 本地文件方式 配置在本地文件中,獲取完之後去更新最新值
- 數據庫方式 與上面類似,只是存儲媒介換成了數據庫而以
- 本地時間戳方式 64 位二進制 (42(毫秒)+5(機器 ID)+5(業務編碼)+12(重複累加)
- 分佈式ZK id生成器
- zk遞增方式
- 自增長主鍵 Mycat自增長主鍵
5、高可用實現
5.1、實現思路探究
從Mycat作爲一個無狀態的數據庫中間件定位來看,高可用只要考慮兩個點:
- MYSQL節點本身的高可用;這個可以參考另一篇轉載的博文五大常見的MySQL高可用方案
- Mycat自身的高可用;可以使用的LVS/HAPROXY或者專門的負載均衡的硬件,通過部署多個Mycat節點來實現高可用。如果擔心負載均衡本身的高可用,可以使用keepalive來組合使用。參考如下圖片
5.2、故障之後又是如何恢復的呢?
如果出現了異常,就先把機器摘下來,等手動恢復正常,追上master數據之後,就可以再以只讀節點加入體系。
6、事務實現原理
單實例的事務處理在這裏肯定沒法直接有用了,這個時候必須要用到分佈式提交協議(兩階段協議/三階段協議/Paxos協議/Zookeeper)
我以爲Mycat提供了幾個XA實現,沒想到還是挺弱的。如果有分片出錯,Mycat可以保證全部能夠回滾成功,因爲就是超時了,也可以保證不會提交成功的。但是卻沒有辦法保證全部commit成功。