Mysql主從同步架構
Mysql集群通常指Mysql的主從復制架構,架構為一主多從,通過邏輯復制的方式把主庫數據復制到從庫,但主從之間無法保證嚴格一致的模式,會帶來主從“數據一致性”的問題。
Mysql主從復制原理
主從同步步驟:
- 主庫將變更寫入
binlog
日志 - 從庫連接到主庫后會有一個IO進程把主庫的
binlog
復制過來,寫入一個中繼日志中 - 從庫的一個sql進程會從中繼日志中讀取
sql
然后執行
注意點:
- 從庫同步主庫的數據是串行化的,也就是說在主庫並行的操作,在從庫會串行化執行。在高並發場景下,從庫的數據是一定會比主庫慢一些的,是有延時的,所以經常出現,剛寫入主庫的數據可能是讀不到的,要過幾十毫秒,甚至幾百毫秒才能讀取到。
- 如果主庫突然宕機,數據恰好沒有同步到從庫,那么從庫就會產生數據丟失的問題
解決Mysql主從同步數據一致性的問題
1. mysql的主從復制機制
首先看mysql在主從復制這塊使用的三種機制:
- 異步復制
- 半同步復制
- 全同步復制(組復制)
異步復制
mysql的默認復制機制是異步的,主庫執行完客戶端提交的事務后會立刻把結果返回給客戶端,並不關心從庫是否接收並處理,會導致如果主DB宕機了,就可能導致主機上提交的事務可能並沒有同步到從db中,主從之間無法保證嚴格一致的模式
半同步復制
- 介於異步復制和並行復制之間,MySQL在5.5中引入了半同步復制,主庫執行完客戶端提交的事務后並不會立刻返回給客戶端,而是強制立即將數據同步給從庫,從庫將日志寫入到自己的reply log中后,接着會返回一個ack給主庫,主庫等待至少一個從庫接收到ack才返回給客戶端;相對於異步復制,提高了數據的安全性,但也提高了延遲,最少是一個TCP/IP往返的時間,所以最好在低延遲的網絡中使用
- 半同步復制通過
rpl_semi_sync_master_wait_point
參數來控制主庫在哪個環節接收從庫的ack,該參數有兩個選項:WAIT_AFTER_SYNC
、WAIT_AFTER_COMMIT
配置為WAIT_AFTER_COMMIT
時:
如上圖所示,會帶來兩個問題:
- 提交的調用在主db提交之后,雖然沒有返回給客戶端,但是事務已經提交了,其他客戶端會讀取到已提交的數據;
- 如果從庫還沒有讀到該事務,但是主庫宕機了,切換到了其他從庫,那么之前讀到的事務就不見了,就出現了數據不一致的問題,如果主庫永遠啟動不了,那么實際上在主庫已經成功提交的事務,在從庫上是找不到的,也就是數據丟失了。
配置為WAIT_AFTER_SYNC
時:
mysql針對上面的問題,在5.7引入了Loss-less Semi-Synchronous
,就是說在調用binlog sync
之后,主庫engine層會等待從庫的ack再進行提交,這樣只有確認了從庫收到了事務之后,主庫才會進行提交。
雖然WAIT_AFTER_SYNC
解決了WAIT_AFTER_COMMIT
模式帶來的數據一致性的問題,但是也帶來了新的問題:
當主庫binlog flush
之后而且把事務發送到了從庫,但在等待從庫ack的過程中宕機了,很明顯這個事務在主庫上是未提交成功的,會被回滾掉,但由於從庫已經收到了事務並執行成功,相當於從庫上多出了數據,從而可能導致數據不一致;
但無論配置的哪種模式,在主庫等待從庫ack的過程中超時退化成了異步,都會導致數據一致性的問題
優點:
- 利用數據庫原生功能,比較簡單
- 可以降低數據一致性風險,提高數據安全性
缺點:
- 主庫的寫請求時延會增長,吞吐量會降低
- 只能提高數據安全性,並不能保證絕對的數據一致性
全同步復制(組復制)
所謂全同步復制(組復制),指的是從庫會開啟多個線程,並行去讀取relay log中不同庫的日志,然后並行重放不同庫的日志,這是庫級別的並行,是MySQL 5.7.17開始引入的新功能,為主從復制實現高可用功能,它支持單主模型和多主模型,默認是單主模型。
- 單主模型:從復制組中眾多個MySQL節點中自動選舉一個
master
節點,只有master
節點可以寫,其他節點自動設置為read only
;當master
節點故障時,會自動選舉一個新的master
節點,選舉成功后,它將設置為可寫,其他slave
將指向這個新的master
- 多主模型:復制組中的任何一個節點都可以寫,因此沒有
master
和slave
的概念
組復制原理:
- 復制組由多個
server
成員構成,並且組中的每個server
成員可以獨立地執行事務 - 所有讀寫(
RW
)事務只有在沖突檢測成功后才會提交。只讀(RO
)事務不需要在沖突檢測,可以立即提交
- 簡單來說,就是對於任何的
RW事務
,提交操作都不是有始發的server單向決定的,而是由組來決定的。 - 在始發server上,當事務准備提交時,該 server 會廣播寫入值(已改變的行)和對應的寫入集(已更新的行的唯一標識符),然后會為該事務建立一個全局的順序。最終,這意味着所有 server 成員以相同的順序接收同一組事務。因此,所有 server 成員以相同的順序應用相同的更改,以確保組內一致。
優點:
- 組復制能夠根據在一組 server 中復制系統的狀態來創建具有冗余的容錯系統。
- 因此,只要它不是全部或多數 server 發生故障,即使有一些 server 故障,系統仍然可用,最多只是性能和可伸縮性降低,但它仍然可用。
- server 故障是孤立並且獨立的。它們由組成員服務來監控,組成員服務依賴於分布式故障檢測系統,其能夠在任何 server 自願地或由於意外停止而離開組時發出信號。
- 提供了高可用性,高彈性,可靠的 MySQL 服務
缺點:
1效率很低,當master節點寫數據的時候,會等待所有的slave節點完成數據的復制,然后才繼續往下進行組復制的每一個節點都可能是slave
2. 使用數據庫中間件
- 所有的讀寫都走數據庫中間件,通常情況下,寫請求路由到主庫,讀請求路由到從庫
- 記錄所有路由到寫庫的key,在主從同步時間窗口內(假設是500ms),如果有讀請求訪問中間件,此時有可能從庫還是舊數據,就把這個key上的讀請求路由到主庫
- 在主從同步時間過完后,對應key的讀請求繼續路由到從庫
常用的數據庫中間件:canal
、otter
等
優點:
- 保證數據絕對一致
缺點:
- 實現成本較高
3. 緩存記錄寫key法
寫:
- 如果key要發生寫操作,記錄在cache里,並根據經驗設置的cache超時時間,例如500ms
- 然后修改主數據庫
讀
- 先到緩存里查看,對應key有沒有相關數據
- 有相關數據,說明緩存命中,這個key剛發生過寫操作,此時需要將請求路由到主庫讀最新的數據
- 如果緩存沒有命中,說明這個key上近期沒有發生過寫操作,此時將請求路由到從庫,繼續讀寫分離
優點:
- 相對數據庫中間件,實現成本較低
缺點:
- 為了保證“一致性”,引入了一個cache組件,並且讀寫數據庫時都多了緩存操作