大廠都在用的MySQL主從複製、讀寫分離及高可用方案 1 單機 =》集羣 2 MySQL主從複製 3 主從複製的缺點及解決方案

1 單機 =》集羣

隨着數據量的增大,讀寫併發的增加,系統可用性要求的提升,單機 MySQL 出現危機:

  • 容量問題,難以擴容,考慮數據庫拆分、分庫分表
  • 讀寫壓力,QPS 過大,特別是分析類需求會影響到業務事務,考慮多機集羣、主從複製
  • 高可用性不足,易宕機,考慮故障轉移、MHA/MGR/Orchestrator
  • 高峯時數據庫連接數經常超過上限

一致性問題,考慮分佈式事務,X/A 柔性事務

讀寫分離的實現是基於主從複製架構:一主多從,只寫主庫,主庫會自動將數據同步到從庫。

爲什麼要讀寫分離?

高併發場景下MySQL的一種優化方案,依靠主從複製使得MySQL實現了數據複製爲多份,增強了抵抗 高併發讀請求的能力,提升了MySQL查詢性能同時,也提升了數據的安全性。當某一個MySQL節點,無論是主庫還是從庫故障時,還有其他的節點中存儲着全量數據,保證數據不會丟失。

主庫將變更寫binlog日誌,然後從庫連接到主庫後,從庫有個I/O線程,將主庫的binlog日誌拷貝到本地,寫入一箇中繼日誌。
接着從庫中有一個SQL線程會從中繼日誌讀取binlog,然後執行binlog日誌中的內容。即在本地再次執行一遍SQL,確保跟主庫的數據相同。

2 MySQL主從複製

2.1 發展史

2000年,MySQL 3.23.15版本引入了複製
2002年,MySQL 4.0.2版本分離 IO 和 SQL 線程,引入了 relay log
2010年,MySQL 5.5版本引入半同步複製
2016年,MySQL 在5.7.17中引入 InnoDB Group Replication

2.2 核心

  • 主庫寫 binlog
  • 從庫 relay log


binlog格式

  • ROW
    記錄詳細但日誌量會比較大
  • Statement
    只是記錄SQL,記錄簡單
    沒有查詢語句
  • Mixed
# 查看binlog
mysqlbinlog -vv mysql-bin.000005

異步複製

異步複製:經典的主從複製,Primary-Secondary Replication,2000年MySQL 3.23.15版本引入 Replication。

傳統的MySQL複製提供了一種簡單的主從複製方案。有一個主(source)並且有一或多個從(replicas)。主數據庫execute事務,將其commit,然後將它們稍後(異步)發送給從數據庫,以re-executed(在基於語句的複製中)或apply(在基於行的複製中)。它是一個無共享系統,默認情況下所有服務器都具有數據的完整副本。

  • MySQL Asynchronous Replication


優點

簡單

缺點

  • 網絡或機器故障,會造成數據不一致

SQL的每個增刪改的會改變數據的操作,除了更新數據外,對這個增刪改操作還會寫入一個日誌文件,記錄這個操作的日誌,即binlog。

mysql 5.7新版本的並行複製,多個SQL線程,每個線程從relay日誌裏讀一個庫的
日誌,重放。
從庫同步主庫數據的過程是串行化的,即主庫上並行的操作,在從庫上會串行執行。
由於從庫從主庫拷貝日誌以及串行執行SQL的特點,在高併發下就有延時,從庫數據一定比主庫慢,所以經常出現,剛寫入主庫的數據讀不到,要過幾十甚至幾百ms才能讀到。
從庫串行化過程:

  1. 讀取binlog日誌
  2. 寫relay日誌、應用日誌變更到自己本地數據

從庫的I/O線程,讀取主庫的binlog日誌時,老版本是單線程,5.6.x之後的新版本改爲多線程讀取。

若主庫宕機時,恰好數據還沒同步到從庫,則有些數據可能在從庫上沒有,可能就這麼丟失了。

所以MySQL實際上在這有兩個機制

半同步複製,它向協議添加了一個同步步驟。這意味着主數據庫在提交時等待從數據庫確認已接收到事務。只有這樣,主數據庫纔會恢復提交操作。

半同步複製

2010 年引入Semisynchronous Replication,5.5 可用,解決主庫數據丟失問題,保證 Source 和 Replica 的最終一致性。
需要啓用插件。



  1. 主庫寫入binlog日誌後,會強制立即將數據同步到從庫
  2. 從庫將日誌寫入自己的relay log後,會返回ack給主庫
  3. 主庫接收到至少一個從庫的ack後纔會認爲寫操作完成

上面的圖片可看到經典的異步MySQL複製協議(及其半同步變量)的示意圖。不同實例之間的箭頭表示服務器之間交換的消息或服務器與客戶端應用程序之間交換的消息。

組複製

2016年引入,5.7 開始,啓用插件。


基於 Paxos 協議實現的組複製,保證數據一致性。

組複製是一種可用於實施容錯系統的技術。複製組是一組服務器,每個服務器都有自己的完整數據副本(無共享複製方案),並通過消息傳遞相互交互。通信層提供了一組保證,例如原子消息和總訂單消息傳遞。這些功能非常強大,可以轉化爲非常有用的抽象,可以用來構建更高級的數據庫複製解決方案。

MySQL組複製建立在這些屬性和抽象之上,並在所有複製協議中實現多源更新。一個複製組由多個服務器組成,該組中的每個服務器可以隨時獨立執行事務。但是,所有讀寫事務只有在組批准後才提交。換句話說,對於任何讀寫事務,組都需要決定是否提交,因此提交操作不是來自原始服務器的單方面決定。只讀事務無需組內的任何協調即可立即提交。

當讀寫事務準備好在原始服務器上提交時,服務器自動廣播寫值(已更改的行)和相應的寫集(已更新的行的唯一標識符)。由於事務是通過原子廣播發送的,因此該組中的所有服務器都將接收該事務,否則將不會。如果他們收到了,那麼相對於之前發送的其他事務,他們都將以相同的順序收到它。因此,所有服務器都以相同的順序接收相同的交易集,並且爲交易建立了全局總訂單。

但是,在不同服務器上同時執行的事務之間可能存在衝突。通過在稱爲認證的過程中檢查並比較兩個不同併發事務的寫集,可以檢測到此類衝突。在認證過程中,衝突檢測是在行級別執行的:如果在不同服務器上執行的兩個併發事務更新同一行,則存在衝突。衝突解決過程指出,已首先訂購的事務在所有服務器上提交,而已訂購第二的事務中止,因此在原始服務器上回滾並由組中的其他服務器丟棄。例如,如果t1和t2在不同的站點上同時執行,都更改了同一行,並且t2在t1之前排序,則t2贏得了衝突,並且t1被回滾。這實際上是一個分佈式的首次提交勝出規則。請注意,如果兩個事務之間的衝突經常發生,那麼在同一個服務器上啓動它們是一個好習慣,在那裏,它們有機會在本地鎖管理器上進行同步,而不必由於認證而回滾。

對於應用和外部化已認證的交易,如果不破壞一致性和有效性,組複製允許服務器偏離交易的約定順序。組複製是最終的一致性系統,這意味着一旦傳入流量減慢或停止,所有組成員將具有相同的數據內容。當流量在流動時,可以按略有不同的順序對事務進行外部化,或者對某些成員先進行外部化。例如,在多主要模式下,儘管尚未應用全局順序中較早的遠程事務,但是本地事務可能會在認證後立即被外部化。當證明過程確定交易之間沒有衝突時,這是允許的。在單主模式下,在主服務器上,併發,無衝突的本地事務以與組複製所同意的全局順序不同的順序進行提交和外部化的可能性很小。在不接受來自客戶端的寫操作的輔助服務器上,事務始終按照約定的順序進行提交和外部化。

下圖描述了MySQL組複製協議,通過將其與MySQL複製(甚至MySQL半同步複製)進行比較,您可以看到一些區別。請注意,爲清楚起見,此圖中缺少一些基本的共識和Paxos相關的消息。


3 主從複製的缺點及解決方案

3.1 主從延遲

  • 只能數據分片,把數據量做小

主從同步適用場景

推薦在讀 >> 寫,且讀時對數據時效性要求不高時採用。所以可以考慮用MySQL的並行複製,但問題是那是庫級別的並行,所以有時作用不是很大。

主從延遲嚴重解決方案

  1. 分庫 : 將一個主庫拆分,每個主庫的寫併發就降低了,主從延遲即可忽略不計
  2. 打開MySQL支持的並行複製,多個庫並行複製,若某個庫的寫入併發特別高,寫併發達到了2000/s,並行複製還是沒意義。二八法則,很多時候比如說,就是少數的幾個訂單表,寫入了2000/s,其他幾十個表10/s。
    從庫開啓多線程,並行讀取relay log中不同庫的日誌,然後並行重放不同庫的日誌,這是庫級別的並行
  3. 重構代碼 : 重構代碼,插入數據後,直接更新,不查詢
  4. 若確實存在必須先插入,立馬要求查詢,然後立馬就反過來執行一些操作,對這個查詢設置直連主庫(不推薦,這會導致讀寫分離失去意義)

3.2 應用側需要配合讀寫分離框架

讀寫分離

藉助於主從複製,我們現在有了多個 MySQL 服務器示例。
如果藉助這個新的集羣,改進我們的業務系統數據處理能力?

最簡單的就是配置多個數據源,實現讀寫分離

動態切換數據源

  1. 基於 Spring/Spring Boot,配置多個數據源(例如2個,master 和 slave)
  2. 根據具體的 Service 方法是否會操作數據,注入不同的數據源,1.0版本

優化:
1.1:基於操作 AbstractRoutingDataSource 和自定義註解 readOnly 之類的,簡化自動切換數據源
1.2:支持配置多個從庫
1.3:支持多個從庫的負載均衡


框架

“動態切換數據源”版問題:

  • 代碼侵入性強
  • 降低侵入性會導致”寫後立即讀”不一致問題
    寫時(還沒同步到從庫),立馬讀(從庫),導致你 insert 數據後去查卻查不到!

改進方式,ShardingSphere-jdbc 的 Master-Slave 功能
1)SQL 解析和事務管理,自動實現讀寫分離
2)解決”寫完讀”不一致的問題
只要一個事務中解析到有寫,所有讀都讀主庫,而無需我們業務代碼處理。

數據庫中間件

“框架版本”的問題?

  • 對業務系統還是有侵入
  • 對已存在的舊系統改造不友好

優化方案:MyCat/ShardingSphere-Proxy 的 Master-Slave 功能

  • 需要部署一箇中間件,規則配置在中間件
  • 模擬一個 MySQL 服務器,對業務系統無侵入

但是該方案需要單獨部署中間件,需要運維成本和領導審批,所以一般開發人員使用框架方案。

3.3 無法高可用

3.3.1 爲什麼要高可用

1、讀寫分離,提升讀的處理能力
2、故障轉移,提供 failover 能力

加上業務側連接池的心跳重試,實現斷線重連,業務不間斷,降低RTO和RPO。

高可用意味着,更少的不可服務時間。一般用SLA/SLO衡量。

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分鐘

3.3.2 failover,故障轉移,災難恢復

容災:熱備與冷備
對於主從來說,就是主掛了,某一個從,變成主,整個集羣來看,正常對外提供服務。
常見的一些策略:

  • 多個實例不在一個主機/機架上
  • 跨機房和可用區部署
  • 兩地三中心容災高可用方案

3.3.3 高可用方案

3.3.3.1 主從手動切換

如果主節點掛掉,將某個從改成主;重新配置其他從節點。修改應用數據源配置。
缺點:

  1. 可能數據不一致
  2. 需要人工干預
  3. 代碼和配置的侵入性

3.3.3.2 主從手動切換

用 LVS+Keepalived 實現多個節點的探活+請求路由。
配置 VIP 或 DNS 實現配置不變更。
缺點:

  • 手工處理主從切換
  • 大量的配置和腳本定義

只能算半自動。

3.3.3.2 MHA

MHA,Master High Availability,目前在 MySQL 高可用方面是一個相對成熟的解決方案,它由日本 DeNA 公司的 youshimaton(現就職於 Facebook)開發,是一套優秀的作爲 MySQL 高可用性環境下故障切換和主從提升的高可用軟件。


基於 Perl 語言開發,一般能在30s內實現主從切換。
切換時,直接通過 SSH 複製主節點的日誌。

缺點:

  • 需要配置 SSH 信息
  • 至少3臺

3.3.3.2 MGR

不借助外部力量,只使用 MySQL 本身。如果主節點掛掉,將自動選擇某個從改成主;無需人工干預,基於組複製,保證數據一致性。


缺點:

  • 外部獲得狀態變更需要讀取數據庫
  • 外部需要使用 LVS/VIP 配置

特點:

  • 高一致性
    基於分佈式Paxos協議實現組複製,保證數據一致性
  • 高容錯性
    自動檢測機制,只要不是大多數節點都宕機就可繼續工作,內置防腦裂保護機制
  • 高擴展性
    節點的增加與移除會自動更新組成員信息,新節點加入後,自動從其他節點同步增量數據,直到與其他節點數據一致
  • 高靈活性
    提供單主模式和多主模式,單主模式在主庫宕機後能夠自動選主,所有寫入都在主節點進行,多主模式支持多節點寫入

適用場景:

  • 彈性複製
    需要非常流暢的複製基礎架構的環境,其中服務器的數量必須動態地增長或縮減,而最少儘可能的痛苦。


  • 高可用分片
    Sharding is a popular approach to achieve write scale-out. Users can use MySQL Group Replication to implement highly available shards. Each shard
    can map into a Replication Group.
    分片是實現寫橫向擴展的一種流行方法。用戶可以使用MySQL組複製來實現高度可用的分片。每個分片可以映射到副本組。


3.3.3.4 MySQL Cluster

完整的數據庫層高可用解決方案。
MySQL InnoDB Cluster是一個高可用的框架,構成組件:

  • MySQL Group Replication
    提供DB的擴展、自動故障轉移
  • MySQL Router
    輕量級中間件,提供應用程序連接目標的故障轉移。MySQL Router是一個輕量級的中間件,可以提供負載均衡和應用連接的故障轉移。它是MySQL團隊爲MGR量身打造的,通過使用Router和Shell,用戶可以利用MGR實現完整的數據庫層的解決方案。如果您在使用MGR,請一定配合使用Router和Shell,可以理解爲它們是爲MGR而生的,會配合MySQl 的開發路線圖發展的工具。
  • MySQL Shell
    新的MySQL客戶端,多種接口模式。可以設置羣組複製及Router。MySQL Shell是MySQL團隊打造的一個統一的客戶端, 它可以對MySQL執行數據操作和管理。它支持通過JavaScript,Python,SQL對關係型數據模式和文檔型數據模式進行操作。使用它可以輕鬆配置管理InnoDB Cluster。


3.3.3.5 Orchestrator

如果主節點掛掉,將某個從改成主。
一款MySQL高可用和複製拓撲管理工具,支持複製拓撲結構的調整,自動故障轉移和手動主從切換等。後端數據庫用MySQL或SQLite存儲元數據,並提供Web界面展示MySQl 複製的拓撲關係及狀態,通過Web可更改MySQL實例的複製關係和部分配置信息,同時也提供命令行和API接口,方便運維管理。

特點:

  1. 自動發現MySQL的復 制拓撲,並且在web.上展示;
  2. 重構複製關係, 可以在web進行拖圖來進行復制關係變更;
  3. 檢測主異常,並可以自動或手動恢復,通過Hooks進行自定義腳本;
  4. 支持命令行和web界面管理複製。

基於 Go 語言開發,實現了中間件本身的高可用。

兩種部署方式
orchestrator/raft:

  1. 數據一致性由orchestrator的raft協議保證
  2. 數據庫之間不通信
    orchestrator/[galera | xtradb cluster | innodb cluster]:
  3. 數據一致性由數據庫集羣保證
  4. 數據庫結點之間通信

如果不部署client

  1. 使用HTTP (/api/leader-check)查詢並路由到主節點

優勢:
能直接在 UI 界面
拖拽改變主從關係


參考

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章