大廠都在用的MySQL主從復制、讀寫分離及高可用方案

1 單機 =》集群

隨著數(shù)據(jù)量的增大,讀寫并發(fā)的增加,系統(tǒng)可用性要求的提升,單機 MySQL 出現(xiàn)危機:

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

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

讀寫分離的實現(xiàn)是基于主從復制架構:一主多從,只寫主庫,主庫會自動將數(shù)據(jù)同步到從庫。

為什么要讀寫分離?

高并發(fā)場景下MySQL的一種優(yōu)化方案,依靠主從復制使得MySQL實現(xiàn)了數(shù)據(jù)復制為多份,增強了抵抗 高并發(fā)讀請求的能力,提升了MySQL查詢性能同時,也提升了數(shù)據(jù)的安全性。當某一個MySQL節(jié)點,無論是主庫還是從庫故障時,還有其他的節(jié)點中存儲著全量數(shù)據(jù),保證數(shù)據(jù)不會丟失。

主庫將變更寫binlog日志,然后從庫連接到主庫后,從庫有個I/O線程,將主庫的binlog日志拷貝到本地,寫入一個中繼日志。
接著從庫中有一個SQL線程會從中繼日志讀取binlog,然后執(zhí)行binlog日志中的內容。即在本地再次執(zhí)行一遍SQL,確保跟主庫的數(shù)據(jù)相同。

2 MySQL主從復制

2.1 發(fā)展史

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


    image

binlog格式

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

異步復制

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

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

  • MySQL Asynchronous Replication


    image
    image

優(yōu)點

簡單

缺點

  • 網絡或機器故障,會造成數(shù)據(jù)不一致

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

mysql 5.7新版本的并行復制,多個SQL線程,每個線程從relay日志里讀一個庫的
日志,重放。
從庫同步主庫數(shù)據(jù)的過程是串行化的,即主庫上并行的操作,在從庫上會串行執(zhí)行。
由于從庫從主庫拷貝日志以及串行執(zhí)行SQL的特點,在高并發(fā)下就有延時,從庫數(shù)據(jù)一定比主庫慢,所以經常出現(xiàn),剛寫入主庫的數(shù)據(jù)讀不到,要過幾十甚至幾百ms才能讀到。
從庫串行化過程:

  1. 讀取binlog日志
  2. 寫relay日志、應用日志變更到自己本地數(shù)據(jù)

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

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

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

半同步復制,它向協(xié)議添加了一個同步步驟。這意味著主數(shù)據(jù)庫在提交時等待從數(shù)據(jù)庫確認已接收到事務。只有這樣,主數(shù)據(jù)庫才會恢復提交操作。

半同步復制

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


image

image
  1. 主庫寫入binlog日志后,會強制立即將數(shù)據(jù)同步到從庫
  2. 從庫將日志寫入自己的relay log后,會返回ack給主庫
  3. 主庫接收到至少一個從庫的ack后才會認為寫操作完成

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

組復制

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


image

基于 Paxos 協(xié)議實現(xiàn)的組復制,保證數(shù)據(jù)一致性。

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

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

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

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

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

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


image

3 主從復制的缺點及解決方案

3.1 主從延遲

  • 只能數(shù)據(jù)分片,把數(shù)據(jù)量做小

主從同步適用場景

推薦在讀 >> 寫,且讀時對數(shù)據(jù)時效性要求不高時采用。所以可以考慮用MySQL的并行復制,但問題是那是庫級別的并行,所以有時作用不是很大。

主從延遲嚴重解決方案

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

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

讀寫分離

借助于主從復制,我們現(xiàn)在有了多個 MySQL 服務器示例。
如果借助這個新的集群,改進我們的業(yè)務系統(tǒng)數(shù)據(jù)處理能力?

最簡單的就是配置多個數(shù)據(jù)源,實現(xiàn)讀寫分離

動態(tài)切換數(shù)據(jù)源

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

優(yōu)化:
1.1:基于操作 AbstractRoutingDataSource 和自定義注解 readOnly 之類的,簡化自動切換數(shù)據(jù)源
1.2:支持配置多個從庫
1.3:支持多個從庫的負載均衡


image

框架

“動態(tài)切換數(shù)據(jù)源”版問題:

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

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

數(shù)據(jù)庫中間件

“框架版本”的問題?

  • 對業(yè)務系統(tǒng)還是有侵入
  • 對已存在的舊系統(tǒng)改造不友好

優(yōu)化方案:MyCat/ShardingSphere-Proxy 的 Master-Slave 功能

  • 需要部署一個中間件,規(guī)則配置在中間件
  • 模擬一個 MySQL 服務器,對業(yè)務系統(tǒng)無侵入

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

3.3 無法高可用

3.3.1 為什么要高可用

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

加上業(yè)務側連接池的心跳重試,實現(xiàn)斷線重連,業(yè)務不間斷,降低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,故障轉移,災難恢復

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

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

3.3.3 高可用方案

3.3.3.1 主從手動切換

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

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

3.3.3.2 主從手動切換

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

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

只能算半自動。

3.3.3.2 MHA

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


image

基于 Perl 語言開發(fā),一般能在30s內實現(xiàn)主從切換。
切換時,直接通過 SSH 復制主節(jié)點的日志。

缺點:

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

3.3.3.2 MGR

不借助外部力量,只使用 MySQL 本身。如果主節(jié)點掛掉,將自動選擇某個從改成主;無需人工干預,基于組復制,保證數(shù)據(jù)一致性。


image

缺點:

  • 外部獲得狀態(tài)變更需要讀取數(shù)據(jù)庫
  • 外部需要使用 LVS/VIP 配置

特點:

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

適用場景:

  • 彈性復制
    需要非常流暢的復制基礎架構的環(huán)境,其中服務器的數(shù)量必須動態(tài)地增長或縮減,而最少盡可能的痛苦。


    image
  • 高可用分片
    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.
    分片是實現(xiàn)寫橫向擴展的一種流行方法。用戶可以使用MySQL組復制來實現(xiàn)高度可用的分片。每個分片可以映射到副本組。


    image

3.3.3.4 MySQL Cluster

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

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


    image

3.3.3.5 Orchestrator

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

特點:

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

基于 Go 語言開發(fā),實現(xiàn)了中間件本身的高可用。

兩種部署方式
orchestrator/raft:

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

如果不部署client

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

優(yōu)勢:
能直接在 UI 界面
拖拽改變主從關系


image

參考

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容