一、數據庫拆分
1. 為什么要做數據庫拆分
單機數據庫存在的問題?
從容量、性能、可用性和運維成本上難以滿足海量數據的場景。
- 性能方面,數據量超過一定閾值,B+樹索引慎獨增加導致磁盤訪問的IO次數增加,進而導致查詢性能的下降。
- 容量方面,單機能存儲的數據量有限
- 可用性方面,大量的查詢落到單一的數據庫節點或者簡單的主從架構上,數據庫很難承擔。
- 運維方面,數據量達到一定閾值,主從同步延遲高、增加字段索引、備份這些都會很慢,影響業務系統。
主從結構解決了高可用、讀擴展。但是單機容量不變,單機寫性能無法解決。
為了解決這些問題,我們需要采用分庫分表,將數據庫拆分開。降低單個節點的寫壓力,提升整個系統的數據容量上限。
擴展立體方
- X軸:通過clone整個系統復制,集群
- Y軸:通過解耦不同功能復制,業務拆分
- Z軸:通過拆分不同數據擴展,數據分片
2. 垂直拆分
垂直拆分,按照業務緯度分庫分表。
垂直拆庫
將一個數據庫,拆分為多個提供不同業務數據處理能力的數據庫。如:將一個電商的單獨庫拆為用戶庫、訂單庫、商品庫。
垂直拆表
如果單表數據量過大,還需要對單表進行拆分。如:一個200列的訂單主表,拆分為十幾個子表:訂單表、訂單詳情表、訂單收件信息表等。
垂直拆分的優缺點:
優點:
- 單庫(單表)變小,便於管理
- 對性能和容量有提升
- 拆分后,系統和數據復雜度降低
- 可以作為微服務改造的基礎
缺點:
- 庫變多,管理變復雜
- 對業務系統有較強的侵入性
- 改造過程復雜,容易出故障
- 拆分到一定程度就無法繼續拆分
3. 水平拆分
水平拆分就是直接對數據進行分片,有分庫和分表兩個具體方式。不改變數據本身的結構,只是降低單個節點數據量。這樣對業務系統本身的代碼來說不需要做特別大的改動,甚至可以基於一些中間件做到透明。
比如把一個10億條記錄的訂單的單庫單表。按用戶id除以32取模,將單庫拆分為32個庫;再按訂單id除以32取模,每個庫再拆為32個表。這樣就是32*32=1024個表,單個表數據量就只有不到百萬條了。
水平分庫分表
一般來說我們我們的數據都是有創建時間的,可以按時間拆分,按照年、季度、月、天都可以。
或者根據用戶拆分、甚至可以根據一些自定義的復雜的邏輯來拆分。
為什么有時候不建議分表,只建議分庫?
因為分表不能解決容量問題,如果瓶頸在IO(磁盤IO、網絡IO)上,分表也解決不了,因為分表還是在同一個機器,而分庫可以在兩個機器上。
分庫還是分表,如何選擇?
一般情況下,如果數據本身讀寫壓力較大,磁盤IO已經成為瓶頸,那么分庫比分表要好。而使用不同的庫,可以並行提升整個集群的並行數據處理能力。
相反的情況下,可以盡量考慮分表,降低單表的數據量。
水平分庫分表的優缺點:
優點:
- 解決容量問題
- 比垂直拆分對系統影響小
- 部分提升性能和穩定性
缺點:
- 集群規模大,管理復雜
- 復雜SQL支持問題
- 數據遷移問題
- 一致性問題
4. 數據的分類管理
數據的分類管理是指通過對數據進行分類提升數據管理能力。
隨着對業務系統、對數據的分析了解發現,很多數據對質量的要求是不一樣的。
如訂單數據,肯定一致性要求最高,不能丟失。而一些日志數據,中間數據,則沒有那么高的一致性。丟了就丟了。
另外,同一張表里的訂單數據也可以采用不同策略,無效訂單比較多,我們可以定期轉移或清除。(一些交易系統里80%以上的是下單后取消的無意義訂單,所以可以清理它)
如果沒有無效訂單,也可以考慮:
- 最近一周下單但是未支付的訂單,被查詢和支付的可能性較大。而再以前一點的,可以直接取消掉。
- 最近3個月下單的數據,被在線重復查詢和系統統計的可能性最大。
- 3個月以前-3年以內的數據,查詢的可能性小,可以不提供在線查詢
- 3年以上的數據,可以直接不提供任何方式的查詢。
這樣的話,我們就可以根據分類采用一定的手段去優化系統:
- 定義一周內下單但未支付的數據為熱數據,同時放到數據庫和內存
- 定義3個月內的數據為溫數據,放到數據庫,提供正常的查詢操作
- 定義3個月到3年的數據為冷數據,從數據庫刪除,歸檔到一些便宜的磁盤,用壓縮的方式(比如MySQL的tokuDB引擎)存儲,用戶需要查詢的話提工單來查詢
- 定義3年以上的數據為冰數據,備份到磁帶之類的介質上,不提供任何查詢操作。
5. 數據庫中間件
數據庫中間件的技術演進
ShardingSphere是一套開源的分布式數據庫中間件解決方案組成的生態圈,它由JDBC、Proxy和Sidecar(規划中)這3款相互獨立,又能混合部署配合使用的產品組成。它們均提供數據分片、分布式事務和數據庫治理功能,可適用於如Java同構、異構、雲原生等各種多樣化的應用場景。
ShardingSphere-JDBC
框架ShardingSphere-JDBC,可以直接在業務代碼使用,支持常見的數據庫和JDBC。只適用於Java語言。
使用實例:
- 讀寫分離:https://github.com/mmcLine/sharding/
- 分庫分表:https://gitee.com/mmcLine/shardingjdbc-database-example
二、數據遷移
方案一:全量
- 業務系統停機
- 數據庫遷移,校驗一致性
- 業務系統升級,接入新數據庫
如果新數據庫結構一樣,可以dump后全量導入。如果是異構的話,需要用程序處理。
方案二:全量+增量
依賴於數據本身的時間戳
- 先同步數據到最近的某個時間戳(如前一天)
- 然后再發布升級時停機維護
- 再同步最后一段時間的變化數據
- 最后升級業務系統,接入新數據庫。
方案三:binlog+全量+增量
- 通過主庫或從庫的binlog來解析和重新構造數據,實現復制。
- 一般需要中間件工具的支持。
可以實現多線程,斷點續傳,全量或增量的數據同步。
繼而可以做到:
- 實現自定義復雜異構數據結構
- 實現自動擴容和縮容,比如分庫分表到單庫單表、單庫單表到分庫分表、分4個庫到分8個庫等等。
下面介紹一個遷移工具:
ShardingSphere-scaling