MySQL架構演進從主從複製到分庫分表

NO IMAGE

背景

業務飛速發展導致數據規模急速膨脹,單機的數據庫已經無法滿足互聯網業務的發展。

傳統的將數據集中存儲單一數據結節的方案,在容量、性能、可用性和可維護性方面已經難以滿足互聯網海量數據的場景。

從容量方面考慮,單機數據庫容量有限,難以擴容。

從性能方面來說,由於關係型數據庫大多數採用B+樹類型索引,在數據量超過一定的閾值後,索引的深度增加導致對磁盤的隨機IO次數增加,進而導致性能問題。

從可用性方面來說,服務通常設計成無狀態的,這必然導致系統的存儲壓力都集中在數據庫層面,而單一的數據節點,或者簡單的主從架構,已經越來越難以承擔。

從運維角度來看,當數據都集中在一個節點上時,數據備份和恢復的時間成本也隨之數據量上升變得不可控。同時數據丟失導致影響的範圍也會被放大。

MySQL架構演進從主從複製到分庫分表

主從複製

  • 主庫將事務操作(除了查詢以外的操作)記錄到binlog

  • 從庫通過relay log同步數據,實現數據的同步

MySQL架構演進從主從複製到分庫分表

binlog日誌格式

  • row 記錄數據庫操作詳細記錄,包括上線文信息等,文件較大。

  • statement 記錄事務相關的SQL文件。

  • mixed 混合式, 基於row和statement兩種文件格式。

異步複製

2000年,MySQL3.23.15版本引入複製功能,採用異步複製的方式,當網絡或者機器故障,會導致數據不一致。

MySQL架構演進從主從複製到分庫分表

半同步複製

2010年, MySQL 5.5版本引入半同步複製, 半同步複製是指只要一個salve節點返回ack,master節點就可以提交事務了,保證數據庫至少有一個節點完成了數據的同步。

MySQL架構演進從主從複製到分庫分表

組複製

2016年,MysQL在5.7.17中引入InnoDB Group Replication,該方案基於paxos協議實現組內複製,保證數據一致性,paxos協議核心在於過半選舉。

MySQL架構演進從主從複製到分庫分表

主從複製的問題

  • 主從複製延遲,導致”寫完讀”數據不一致問題。

    • 從庫讀取失敗,再去主庫執行一遍SQL,存在性能問題。

    • 業務層保證系統核心功能可用,將核心功能的CRUD操作都路由到主庫,非核心業務功能即使存在短暫數據不一致也影響不大。

  • 路由問題,需要業務層根據SQL路由到不同的數據庫,路由到SLAVE節點時,還需要保證系統負載均衡。

    • 業務層通過框架(如sharding-jdbc)或者手動實現,對業務的侵入性較大,已存在的舊系統改造不友好。

    • 通過數據庫中間件實現(如mycat、sharding-proxy),需要部署一箇中間件(中間件實現SQL標準),規則配置在中間件,執行過程中會多一次網絡轉發。

  • 不能保證系統高可用

    • 通過一系列高可用的解決方案保證數據庫高可用

數據庫高可用

什麼是高可用?

高可用意味著,更少的服務不可用的時間,一般用SLA(服務級別協議)衡量。

1年 = 365天 = 8760小時

99 = 8760 * 1% = 8760 * 0.01 = 87.6小時

99.9 = 8760 * 0.1% = 8760 * 0.001 = 8.76小時

99.99 = 8760 * 0.0001 = 0.876小時 = 0.876 * 60 = 52.6分鐘

99.999 = 8760 * 0.00001 = 0.0876小時 = 0.0876 * 60 = 5.26分鐘

為什麼要做高可用?

通過故障轉移,提供failover的能力,加上業務側連接池的心跳重試,實現斷線重連,業務不間斷,降低RTO(Recovery Time Objective,復原時間目標)和RPO(Recovery Point Objective,復原點目標)。

  • 容災恢復:冷備和熱備,冷備和熱備的區別在於運行期間是否提供服務。

  • 對於主從來說,簡單的來說就是Master節點掛了,某一個從節點,自動切換成主。

  • 從集群來看,即便是個別節點掛了,能正常對外提供服務。

常見的策略:

  • 多實例部署

  • 跨機房部署

  • 兩地三中心容災高可用方案等。

手動切換

即如果主節點宕機,手動將某個從節點修改成主節點。

存在的問題:

  • 可能數據不一致

  • 需要人工干預

  • 代碼和配置的侵入性,需要配置其他節點,修改應用數據源的配置。

MHA

MHA全稱叫做MySQL Master High Availability,是由Facebook工程師Yoshinori Matsunobu開發的一款MySQL高可用框架,基於Perl語言開發,一般能在30秒內實現主從切換,切換時通過SSH複製主節點的日誌信息。

MHA負責MySQL主庫的高可用,當主庫發生故障時,MHA會選擇一個數量最接近原主庫的候選節點作為新的主節點,並且補齊和之前宕機的Master差異的Binlog。數據補齊後,即將寫VIP漂移到新的主庫上。具體的架構圖如下:

MySQL架構演進從主從複製到分庫分表

優點

  • 可以進行根據具體的故障實現自動檢測和故障轉移

  • 擴展性好,可以任意的擴展數據節點數量

缺點:

  • 極限情況下,可能會發生腦裂現象,出現多個Master。

  • 需要配置SSH信息。

  • 至少需要三臺。

MGR

MGR是數據庫支持的,只需要配置插件即可,如果主節點掛掉,將自動選擇某個從改為主。無需人工干預,並且基於組複製(paxos算法),保證數據一致性。

MySQL架構演進從主從複製到分庫分表

MGR的特點

  • 高一致性,基於分佈式Paxos協議實現複製,保證數據一致性。

  • 高容錯性,自動檢測機制,只要大多數節點都宕機的情況下,數據庫可以繼續工作,內置防腦裂保護機制。

  • 高可擴展性,加入新節點後,自動實現增量同步,直到與其他節點數據一致。

  • 高靈活性,提供了單主和多主模式,單主模式支持主節點宕機,自動選主,多主模式支持多節點寫入。

MySQL InnoDb Cluster,一個完整的數據庫高可用解決框架,由多個組件組成

  • MySQL Group Replication,提供DB的擴展,故障遷移

  • MySQL Router,輕量級中間件,提供應用程序連接目標的故障轉移。

  • MySQL shell,新的MySQL客戶端,多種接口模式,可以設置群組複製和Router。

MySQL架構演進從主從複製到分庫分表

Orchestrator

一款MySQL高可用和複製拓撲管理工具,支持複製拓撲結構的調整,自動故障遷移和手動切換的功能等,直接拖拽UI,就可以實現主從切換。

分庫分表

分庫分表通常是指垂直分庫和水平分表,對於垂直分表其實就是將寬表拆分成小表,沒有太多的技術挑戰,這裡側重講講垂直分庫和水平分表。

垂直分庫

垂直分庫是指將數據庫進行縱向切分,通常按照業務的維度進行劃分。

如典型的微服務的架構,將系統按照業務維度垂直拆分,劃分成多個服務。如一個電商網站可以拆分成:訂單、商品、會員、支付等服務。

MySQL架構演進從主從複製到分庫分表

垂直分庫後業務更加單純,職責單一,同時可以解決部分數據庫容量問題,但是同時也引入了新的技術複雜度,如下:

  • 分佈式事務,跨數據庫的事務操作需要分佈式事務支持,否則系統將會面臨數據不一致的問題。

    • 方案一,採用XA事務,XA事務是數據庫本身支持規範,具備強一致性的特徵,但是性能比較差,對於追求高性能的場景不適合使用XA事務。

    • 方案二,採用柔性事務,柔性事務是指,數據庫保證局部事務,全局事務實現由業務層實現(如通過調度補償,重試補償,人工介入等),柔性事務常見的解決方案有:TCC、利用消息隊列實現事務。

  • join問題,分庫後,表分散到不同的數據庫,無法直接使用SQL進行JOIN操作,需要業務層自己實現聚合操作,增加了開發成本。

水平分表

水平分表是指,將表按照某種規則分成多張表,拆分後的表結構和拆分前完全一致,但是數據分散到多張表中,也可以成為數據分片。

MySQL架構演進從主從複製到分庫分表

通過水平分表,解決了單表的容量和性能問題。但同時,水平分表後,引入了新的技術複雜度,主要有以下幾點:

  • 路由問題,當業務層通過SQL對數據庫進行DML操作時,到底該查詢那張表呢?

    • 方案一:範圍路由。根據表中某一列(分片鍵)的取值範圍進行分表,如根據創建時間將主表分成多張表,每個月的數據單獨存儲在一個表中。範圍路由可能出現數據分配不均勻的現象,但是表數量易於擴展。

    • 方案二:哈希路由。根據表中某一列與分片數量取模運算(field_value % table_num)。hash路由和範圍路由相反。表數量擴展時都會導致數據重新分佈,但是數據分佈較為均勻。

  • join問題,由於分表後,數據分散到多個表中,JOIN的條件語句中如果沒有分片鍵,那麼需要將全部的分片表都JOIN一遍,這種操作會存在性能問題。

  • count問題,分表後,如果需要統計表記錄總和,需要遍歷所有的表,然後再將結果進行彙總,可以通過一張單獨的彙總表來解決,但這種解決方案需要每次insert或者delete的時候就需要更新彙總表,如果有一次沒有更新,就會導致數據不一致。

  • order by問題,分表後,如果需要進行排序,需要遍歷所有的表,然後在代碼層進行重新排序,這個操作一看就會存在性能問題。

分庫分表解決方案

  • 業務代碼層解決,可以通過SQL手動處理路由,但是和業務的耦合很嚴重,不易於維護。通常採用集成jar包的方式進行解決,如集成成熟的開源項目:sharding-jdbc。

  • 數據庫中間件,數據庫中間件實現了對應數據庫的SQL標準,路由規則配置在數據庫中間件,業務代碼操作數據庫中間件和直接操作數據庫沒有任何區別。

總結

從單節點數據庫到主從複製,再到數據庫高可用,再到分庫分表,很好的解決了數據的性能、容量、高可用、運維性等問題,但是會帶來分佈式事務、複雜SQL難以操作、SQL路由等問題。

架構設計應該遵循:”簡單性”、”合適性”、”演化性”的原則,符合當前的業務發展,所以系統設計沒有必要一上來就考慮分庫分表,而應該是數據量達到一定的量,出現性能瓶頸的時候再對系統進行改造和優化。

基於sharing-jdbc實現數據庫讀寫分離

基於sharing-jdbc實現數據庫分庫分表

美團數據庫高可用解決方案

五大常見的MySQL高可用方案

相關文章

一個合格的初級前端工程師需要掌握的模塊筆記

DAY5:你必須知道的java虛擬機之類篇——類文件的加載(1)

在2021年你需要掌握的7種關於JavaScript的數組方法

🏆技術專題第九期|聊聊了不起的Deno