原文鏈接:https://zhuanlan.zhihu.com/p/669450627
一、主從同步概述
mysql主從同步,即MySQL Replication,可以實現將數據從一臺數據庫服務器同步到多臺數據庫服務器。MySQL數據庫自帶主
從同步功能,經過配置,可以實現基于庫、表結構的多種方案的主從同步。可以對MySQL做主從架構并且進行讀寫分離,讓主服務器(Master)處理寫請求,從服務器(Slave)處理讀請求,這樣可以
進一步提升數據庫的并發處理能力,如下圖所示:
二、主從同步作用
一般來說,優先考慮優化sql及索引等,充分發揮數據庫的最大性能;其次是采用緩存的策略,比如使用redis、magodb
等緩存工具,通過其高性能的優勢把數據保存在內存數據庫中,提升讀取的效率,最后才是采取數據庫主從架構,進行讀寫分
離(因為成本高)。
2.1 讀寫分離
通過主從復制的方式來同步數據,之后通過讀寫分離的方法提升數據庫并發處理能力。簡單來說就是數據放在多個數據庫中,其中一
個是Master主庫,其余的是Slave從庫。當主數據庫數據發生變化時,會自動將數據同步到從數據庫中,程序可以設置去從庫
讀取數據,從而實現讀寫分離
2.2 數據備份
主從同步屬于數據熱備份機制,在主庫正常運行下備份,不影響提供查詢服務。
2.3 高可用性
數據備份其實是冗余的機制,通過冗余的方式可以換取數據庫的高可用性,當服務器出現故障、宕機等無可用的情況下,可
以迅速進行故障切換,讓從庫當主庫,保證服務正常運行。
三、主從同步原理
3.1 主從同步流程圖
3.2 主從同步執行流程
1、從庫不斷試探主庫的二進制日志文件(binlog),如果這個文件有更新則發送請求從主庫獲取新的內容;
2、用戶向主庫中寫數據:包括添加、刪除、修改、建庫建表等操作;
3、主庫將寫的命令記錄到二進制文件并更新二進制文件的偏移量;
4、從庫試探主庫二進制文件發現偏移量與從庫中記錄的偏移量值不一樣時表示主庫有更新,那么啟動IO線程向主庫請求從某個偏移量開始到二進制日志文件結束位置之間所有的數據;
5、主庫根據從庫請求,通過binlog dump線程將新偏移量推送到從庫中;
6、從庫獲取主庫的數據后,會將這些命令數據寫入中繼日志文件(relaylog)中,然后喚醒SQL線程同時讓當前的IO線程掛起(休眠等待);
7、SQL線程根據記錄的中繼日志文件的偏移量讀取中繼日志文件中的命令;
8、SQL線程獲取到命令后在本地數據庫進行回放(就是從庫中執行主庫的SQL語句),回放完成當前SQL線程掛機(休眠等待)。
3.3?主從同步線程
msyql 的主從同步通過3個線程完成,其中1個線程在主庫,2個線程在從庫上。
如果一個主庫連接多個從庫,那么主庫將會給每個處于連接狀態的從庫創建一個Binary log dump線程,每個從庫也有自己的同步I/O以及SQL線程。
3.3.1 Binary log dump 線程
當從庫連上主庫時,主庫會創建一個線程來發送 binlog 的內容給從庫。
在數據庫終端執行sql: SHOW PROCESSLIST , 可以看到 Binlog Dump 線程。
binlog dump 線程在binlog中讀取要發送給從庫的數據時,會對binlog加鎖。一旦數據讀取完成,線程將釋放鎖,即使數據還未發送到從庫。
3.3.2?IO 線程
當在從庫上執行sql: START SLAVE ,從庫將創建一個I/O線程。該線程將連接主庫,并請求主庫發送binlog中更新的記錄給從庫。
主庫的Binlog Dump線程,將更新的binlog發送到從庫,從庫的 I/O線程將這些更新入從庫的relay log。
在從庫中執行sql: SHOW SLAVE STATUS, 能夠看到 Slave_IO_running 的狀態。
3.3.3?IO 線程
從庫創建同步SQL線程來讀取 relay log,并執行其中的事務。
一個從庫使用2個線程將從主庫讀取更新以及在從庫執行數據更新分成獨立的任務。因此,從主庫讀取更新的任務不會減慢,即使從庫執行數據更新任務很慢。例如,如果從庫停止運行一段時間后再啟動從庫,從庫的 I/O線程能夠快速獲從主庫取到所有的binlog,即使 SQL 線程滯后。如果從庫在 SQL線程執行所有更新前停止運行, I/O 線程至少獲取到了一份安全的更新binlog并保存到從庫的relay log, 當下次啟動從庫后就可能執行數據更新。
在從庫上通過設置系統變量 slave_parallel_workers 的值大于0(默認值),可以開啟并行處理任務。當該變量設置了,從庫設置創建設置的數量的worker 線程,以及一個協調線程來管理worker 線程。如果你在使用多從庫通道,每個通道都將有這么多線程。slave_parallel_workers大于0從庫一般被稱為多線程從庫(副本)。一旦這么設置,失敗的事務將會被重試。
3.4?Relay log與從庫元數據存儲
從庫(副本)也會記錄從庫(源庫)的binlog的當前位置以及從庫的relay log。
在同步過程中,一個從庫創建多個信息庫。
3.4.1 relay log
該log有 I/O線程寫入,log中的事務來自主庫的binlog,并且將被 SQL線程執行更新到從庫。
3.4.2 從庫連接元數據存儲
包含了從庫I/O線程連接主庫需要的信息,以及從主庫binlog中檢索事務需要的信息。連接元數據存儲被寫進表mysql.slave_master_info或者一個文件中。
3.4.3 從庫的應用程序元數據存儲
包含了從庫SQL線程從relay log讀取事務以及將事務更新到從庫的信息。從庫的應用程序元數據存儲被寫進表mysql.slave_relay_log_info 或者 一個文件中。
從庫連接元數據存儲與從庫的應用程序元數據存儲被統稱為從庫元數據存儲,可以參考更多相關說明
使從庫能夠靈活應對宕機: 事務性存儲引擎InnoDB創建表mysql.slave_master_info 與 表mysql.slave_relay_log_info。從庫的應用程序元數據存儲表更新將與事務一起提交, 也就是記錄在元數據存儲中的從庫進度信息一直與從庫的更新保持一致,即使從庫宕機。
四、解決主從數據一致性
4.1 全同步復制
全同步復制,就是當主庫執行完一個事務之后,要求所有的從庫也都執行完該事物,才可以返回處理結果給客戶端;因此,雖然
全同步復制數據一致性得到保證了,但是主庫完成一個事務需要等待所有從庫完成,性能難免會降低。
4.2 異步復制
異步復制,就是當主庫提交事物后,會通知binlog dump線程發送binlog 日志給從庫,一旦binlog dump線程將binlog 日志
發送給從庫之后,不需要等到從庫也同步完成事物,主庫就會將處理結果返回給客戶端。
主庫只管自己完成事物,就將處理結果返回給客戶端(此時從庫不一定完成同步事物),可能導致主從數據不一致問題,比如剛在
主庫新增的數據,馬上去從庫查詢就可能查詢不到。而且當主庫提交完事物后,如果宕機了,可能會導致binlog 日志未同步給從庫,
同時為了回復故障切換主從節點的話,就會出現數據丟失問題。因此,雖然異步復制性能高,但是數據一致性是最弱的。
mysql主從復制,默認采用的就是異步復制這種復制策略。
4.3 半同步復制
mysql5.5 版本后開始支持半同步復制方式。原理就是在客戶端提交commit之后不直接將結果返回客戶端,而是至少等待至少有一個從
庫收到binlog ,并且寫到中繼日志之后再返回給客戶端。優點:提高數據一致性。缺點:降低主庫寫的效率。
mysql5.7 版本中增加了一個rpl_semi_sync_master_wait_for_slave_count參數,可以根據需要響應的從庫數據庫數量
設置,默認為1,也就是一個從庫有了響應,就返回給客戶端。如果這個參數調大,就可以提高數據一致性。
4.4 增強半同步復制
增強半同步復制,是mysql 5.7.2后的版本對半同步復制做的一個改進,原理上幾乎是一樣的,主要是解決幻讀的問題。
主庫配置了參數 rpl_semi_sync_master_wait_point = AFTER_SYNC 后,主庫在存儲引擎提交事務前,必須先收到從庫數據
同步完成的確認信息后,才能提交事務,以此來解決幻讀問題