收藏了!大廠都在用的MySQL主從複製、讀寫分離及高可用方案
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才能讀到。從庫序列化過程:
-
讀取binlog日誌
-
寫relay日誌、應用日誌變更到自己本地資料
從庫的I/O執行緒,讀取主庫的binlog日誌時,老版本是單執行緒,5.6.x之後的新版本改為多執行緒讀取。
若主庫宕機時,恰好資料還沒同步到從庫,則有些資料可能在從庫上沒有,可能就這麼丟失了。
所以MySQL實際上在這有兩個機制
半同步複製,它向協議添加了一個同步步驟。這意味著主資料庫在提交時等待從資料庫確認已接收到事務。只有這樣,主資料庫才會恢復提交操作。
半同步複製
2010 年引入Semisynchronous Replication,5.5 可用,解決主庫資料丟失問題,保證 Source 和 Replica 的最終一致性。需要啟用外掛。
-
主庫寫入binlog日誌後,會強制立即將資料同步到從庫
-
從庫將日誌寫入自己的relay log後,會返回ack給主庫
-
主庫接收到至少一個從庫的ack後才會認為寫操作完成
上面的圖片可看到經典的非同步MySQL複製協議(及其半同步變數)的示意圖。不同例項之間的箭頭表示伺服器之間交換的訊息或伺服器與客戶端應用程式之間交換的訊息。
組複製
2016年引入,5.7 開始,啟用外掛。
基於 Paxos 協議實現的組複製,保證資料一致性。
組複製是一種可用於實施容錯系統的技術。複製組是一組伺服器,每個伺服器都有自己的完整資料副本(無共享複製方案),並通過訊息傳遞相互互動。通訊層提供了一組保證,例如原子訊息和總訂單訊息傳遞。這些功能非常強大,可以轉化為非常有用的抽象,可以用來構建更高階的資料庫複製解決方案。
MySQL組複製建立在這些屬性和抽象之上,並在所有複製協議中實現多源更新。一個複製組由多個伺服器組成,該組中的每個伺服器可以隨時獨立執行事務。但是,所有讀寫事務只有在組批准後才提交。換句話說,對於任何讀寫事務,組都需要決定是否提交,因此提交操作不是來自原始伺服器的單方面決定。只讀事務無需組內的任何協調即可立即提交。
當讀寫事務準備好在原始伺服器上提交時,伺服器自動廣播寫值(已更改的行)和相應的寫集(已更新的行的唯一識別符號)。由於事務是通過原子廣播發送的,因此該組中的所有伺服器都將接收該事務,否則將不會。如果他們收到了,那麼相對於之前傳送的其他事務,他們都將以相同的順序收到它。因此,所有伺服器都以相同的順序接收相同的交易集,並且為交易建立了全域性總訂單。
但是,在不同伺服器上同時執行的事務之間可能存在衝突。通過在稱為認證的過程中檢查並比較兩個不同併發事務的寫集,可以檢測到此類衝突。在認證過程中,衝突檢測是在行級別執行的:如果在不同伺服器上執行的兩個併發事務更新同一行,則存在衝突。衝突解決過程指出,已首先訂購的事務在所有伺服器上提交,而已訂購第二的事務中止,因此在原始伺服器上回滾並由組中的其他伺服器丟棄。例如,如果t1和t2在不同的站點上同時執行,都更改了同一行,並且t2在t1之前排序,則t2贏得了衝突,並且t1被回滾。這實際上是一個分散式的首次提交勝出規則。請注意,如果兩個事務之間的衝突經常發生,那麼在同一個伺服器上啟動它們是一個好習慣,在那裡,它們有機會在本地鎖管理器上進行同步,而不必由於認證而回滾。
對於應用和外部化已認證的交易,如果不破壞一致性和有效性,組複製允許伺服器偏離交易的約定順序。組複製是最終的一致性系統,這意味著一旦傳入流量減慢或停止,所有組成員將具有相同的資料內容。當流量在流動時,可以按略有不同的順序對事務進行外部化,或者對某些成員先進行外部化。例如,在多主要模式下,儘管尚未應用全域性順序中較早的遠端事務,但是本地事務可能會在認證後立即被外部化。當證明過程確定交易之間沒有衝突時,這是允許的。在單主模式下,在主伺服器上,併發,無衝突的本地事務以與組複製所同意的全域性順序不同的順序進行提交和外部化的可能性很小。在不接受來自客戶端的寫操作的輔助伺服器上,事務始終按照約定的順序進行提交和外部化。
下圖描述了MySQL組複製協議,通過將其與MySQL複製(甚至MySQL半同步複製)進行比較,您可以看到一些區別。請注意,為清楚起見,此圖中缺少一些基本的共識和Paxos相關的訊息。
3 主從複製的缺點及解決方案
3.1 主從延遲
-
只能資料分片,把資料量做小
主從同步適用場景
推薦在讀 >> 寫,且讀時對資料時效性要求不高時採用。所以可以考慮用MySQL的並行複製,但問題是那是庫級別的並行,所以有時作用不是很大。
主從延遲嚴重解決方案
-
分庫 : 將一個主庫拆分,每個主庫的寫併發就降低了,主從延遲即可忽略不計
-
開啟MySQL支援的並行複製,多個庫並行複製,若某個庫的寫入併發特別高,寫併發達到了2000/s,並行複製還是沒意義。二八法則,很多時候比如說,就是少數的幾個訂單表,寫入了2000/s,其他幾十個表10/s。從庫開啟多執行緒,並行讀取relay log中不同庫的日誌,然後並行重放不同庫的日誌,這是庫級別的並行。
-
重構程式碼 : 重構程式碼,插入資料後,直接更新,不查詢
-
若確實存在必須先插入,立馬要求查詢,然後立馬就反過來執行一些操作,對這個查詢設定直連主庫(不推薦,這會導致讀寫分離失去意義)
3.2 應用側需要配合讀寫分離框架
讀寫分離
藉助於主從複製,我們現在有了多個 MySQL 伺服器示例。如果藉助這個新的叢集,改進我們的業務系統資料處理能力?
最簡單的就是配置多個數據源,實現讀寫分離
動態切換資料來源
-
基於 Spring/Spring Boot,配置多個數據源(例如2個,master 和 slave)
-
根據具體的 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 主從手動切換
如果主節點掛掉,將某個從改成主;重新配置其他從節點。修改應用資料來源配置。缺點:
-
可能資料不一致
-
需要人工干預
-
程式碼和配置的侵入性
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介面,方便運維管理。
特點:
-
自動發現MySQL的復 制拓撲,並且在web.上展示;
-
重構複製關係, 可以在web進行拖圖來進行復制關係變更;
-
檢測主異常,並可以自動或手動恢復,通過Hooks進行自定義指令碼;
-
支援命令列和web介面管理複製。
基於 Go 語言開發,實現了中介軟體本身的高可用。
兩種部署方式 orchestrator/raft:
-
資料一致性由orchestrator的raft協議保證
-
資料庫之間不通訊 orchestrator/[galera | xtradb cluster | innodb cluster]:
-
資料一致性由資料庫叢集保證
-
資料庫結點之間通訊
如果不部署client
-
使用HTTP (/api/leader-check)查詢並路由到主節點
優勢:能直接在 UI 介面 拖拽改變主從關係