什麼是主從複製?mysql主從複製?redis主從複製?

什麼是主從複製

是一種數據備份的方案。

簡單來說,是使用兩個或兩個以上相同的數據庫,將一個數據庫當做主數據庫,而另一個數據庫當做從數據庫。主數據庫中進行相應操作時,從數據庫記錄下所有主數據庫的操作,使其二者一模一樣。

image-20200623170950718

爲什麼需要主從複製

  • 讀寫分離:通過主從複製的方式來同步數據,然後通過讀寫分離提高數據庫併發處理能力,提高數據庫的吞吐量。
  • 數據備份:我們通過主從複製將主庫上的數據複製到了從庫上,相當於是一種熱備份機制,也就是在主庫正常運行的情況下進行的備份,不會影響到服務。
  • 高可用性:數據備份實際上是一種冗餘的機制,通過這種冗餘的方式可以換取數據庫的高可用性,也就是當服務器出現故障或宕機的情況下,可以切換到從服務器上,保證服務的正常運行。

mysql的主從複製

實際上主從同步的原理就是基於 Binlog 進行數據同步的。在主從複製過程中,會基於 3 個線程來操作,一個主庫線程,兩個從庫線程。

  • 二進制日誌轉儲線程(Binlog dump thread)是一個主庫線程。當從庫線程連接的時候,主庫可以將二進制日誌發送給從庫,當主庫讀取事件的時候,會在 Binlog 上加鎖,讀取完成之後,再將鎖釋放掉。(當從庫線程連接的時候可以將二進制日誌發送給從庫

  • 從庫 I/O 線程會連接到主庫,向主庫發送請求更新 Binlog。這時從庫的 I/O 線程就可以讀取到主庫的二進制日誌轉儲線程發送的 Binlog 更新部分,並且拷貝到本地形成中繼日誌(Relay log)。(接到主庫,向主庫發送請求更新binlog

  • 從庫 SQL 線程會讀取從庫中的中繼日誌,並且執行日誌中的事件,從而將從庫中的數據與主庫保持同步。(讀取從庫中的中繼日誌,並且執行日誌中的事件

總結:從庫I/O線程向主庫發起更新請求,主庫轉儲線程向從庫發送binlog二進制日誌,作爲中繼日誌,從庫SQL線程從中繼日誌讀取進行同步 (記憶爲:請求–響應–執行)

image-20200623165942887

MySQL複製的兩種方法

(1)傳統方式
基於主庫的bin-log將日誌事件和事件位置複製到從庫,從庫再加以應用來達到主從同步的目的。

(2)GTID方式(global transaction identitifiers)

  • 是基於事物來複制數據,因此也就不依賴日誌文件,同時又能更好的保證主從庫數據一致性。
  • 基於GTID的複製是從Mysql5.6開始支持的一種新的複製方式,此方式與傳統基於日誌的方式存在很大的差異,在原來的基於日誌的複製中,從服務器連接到主服務器並告訴主服務器要從哪個二進制日誌的偏移量開始執行增量同步,這時我們如果指定的日誌偏移量不對,這與可能造成主從數據的不一致,而基於GTID的複製會避免。
  • 在基於GTID的複製中,首先從服務器會告訴主服務器已經在從服務器執行完了哪些事務的GTID值,然後主庫會有把所有沒有在從庫上執行的事務,發送到從庫上進行執行,並且使用GTID的複製可以保證同一個事務只在指定的從庫上執行一次,這樣可以避免由於偏移量的問題造成數據不一致。
  • 什麼是GTID,也就是全局事務ID,其保證爲每一個在主上提交的事務在複製集羣中可以生成一個唯一的ID。

mysql支持的複製類型

基於語句的複製
主服務器上面執行的語句在從服務器上面再執行一遍,在MySQL-3.23版本以後支持。
基於行復制
把主服務器上面改編後的內容直接複製過去,而不關心到底改變該內容是由哪條語句引發的,在MySQL-5.0版本以後引入。
混合複製類型
MySQL默認使用基於語句的複製,當基於語句的複製會引發問題的時候就會使用基於行的複製,MySQL會自動進行選擇。

在MySQL主從複製架構中,讀操作可以在所有的服務器上面進行,而寫操作只能在主服務器上面進行。主從複製架構雖然給讀操作提供了擴展,可如果寫操作也比較多的話(多臺從服務器還要從主服務器上面同步數據),單主模型的複製中主服務器勢必會成爲性能瓶頸。

mysql主從複製數據一致性問題

進行主從同步的內容是二進制日誌,它是一個文件,在進行網絡傳輸的過程中就一定會存在延遲(比如 500ms),這樣就可能造成用戶在從庫上讀取的數據不是最新的數據,也就是主從同步中的數據不一致性問題。 比如我們對一條記錄進行更新,這個操作是在主庫上完成的,而在很短的時間內(比如 100ms)又對同一個記錄進行了讀取,這時候從庫還沒有完成數據的更新,那麼我們通過從庫讀到的數據就是一條舊的記錄。

所以在進行讀寫分離的同時,要解決主從同步中數據不一致的問題,也就是解決主從之間數據複製方式的問題,如果按照數據一致性從弱到強來進行劃分,有以下 3 種複製方式。

方法 1:異步複製

異步模式就是客戶端提交 COMMIT 之後不需要等從庫返回任何結果,而是直接將結果返回給客戶端,這樣做的好處是不會影響主庫寫的效率,但可能會存在主庫宕機,而 Binlog 還沒有同步到從庫的情況,也就是此時的主庫和從庫數據不一致。這時候從從庫中選擇一個作爲新主,那麼新主則可能缺少原來主服務器中已提交的事務。所以,這種複製模式下的數據一致性是最弱的。

image-20200623172429046

方法 2:半同步複製

MySQL5.5 版本之後開始支持半同步複製的方式。原理是在客戶端提交 COMMIT 之後不直接將結果返回給客戶端,而是等待至少有一個從庫接收到了 Binlog,並且寫入到中繼日誌中,再返回給客戶端。 這樣做的好處就是提高了數據的一致性,當然相比於異步複製來說,至少多增加了一個網絡連接的延遲,降低了主庫寫的效率。

在 MySQL5.7 版本中還增加了一個rpl_semi_sync_master_wait_for_slave_count參數,我們可以對應答的從庫數量進行設置,默認爲 1,也就是說只要有 1 個從庫進行了響應,就可以返回給客戶端。如果將這個參數調大,可以提升數據一致性的強度,但也會增加主庫等待從庫響應的時間。

image-20200623172414465

方法 3:組複製

組複製技術,簡稱 MGR(MySQL Group Replication)。是 MySQL 在 5.7.17 版本中推出的一種新的數據複製技術,這種複製技術是基於 Paxos 協議的狀態機複製。

剛纔介紹的異步複製和半同步複製都無法最終保證數據的一致性問題,半同步複製是通過判斷從庫響應的個數來決定是否返回給客戶端,雖然數據一致性相比於異步複製有提升,但仍然無法滿足對數據一致性要求高的場景,比如金融領域。MGR 很好地彌補了這兩種複製模式的不足。

下面我們來看下 MGR 是如何工作的(如下圖所示)。

首先我們將多個節點共同組成一個複製組,在執行讀寫(RW)事務的時候,需要通過一致性協議層(Consensus 層)的同意,也就是讀寫事務想要進行提交,必須要經過組裏“大多數人”(對應 Node 節點)的同意,大多數指的是同意的節點數量需要大於(N/2+1),這樣纔可以進行提交,而不是原發起方一個說了算。而針對只讀(RO)事務則不需要經過組內同意,直接 COMMIT 即可。

在一個複製組內有多個節點組成,它們各自維護了自己的數據副本,並且在一致性協議層實現了原子消息和全局有序消息,從而保證組內數據的一致性。

MGR 將 MySQL 帶入了數據強一致性的時代,是一個劃時代的創新,其中一個重要的原因就是 MGR 是基於 Paxos 協議的。Paxos 算法是由 2013 年的圖靈獎獲得者 Leslie Lamport 於 1990 年提出的,有關這個算法的決策機制你可以去網上搜一下。

事實上,Paxos 算法提出來之後就作爲分佈式一致性算法被廣泛應用,比如 Apache 的 ZooKeeper 也是基於 Paxos 實現的。

image-20200623172354688

三種複製總結

異步複製: 客戶端提交COMMIT之後不需要等到從庫返回任何結果,而是直接將結果返回給客戶端
優點:不會影響主庫寫的效率
缺點:可能會存在主庫宕機,而binlog還沒有同步到從庫的情況,也就是此時的主庫和從庫數據出現不一致的情況。

半異步複製: MySQL5.5版本之後開始支持半同步複製的方式,在客戶端提交COMMIT之後不直接將結果返回給客戶端,而是等待至少有一個從庫接受到了binlog .並且寫入到中繼日誌中.再進行返回給客戶端。
優點:提升了數據一致性

不足:仍然存在數據不一致性的情況,增加了網絡連接的延遲

MGR複製: 簡稱MGR ,是MySQL在5.7.17版本中推出的一種新的數據複製技術,這種複製技術是基於Paxos協議的狀態機複製。Paxos協議可以解決分佈式系統中出現的數據不一致的問題
優點:提供了數據強-致性.可以讓MySQL應用到更多領域,比如金融
不足:對網絡性能要求高,只支持InnoDB存儲引擎

redis的主從複製

在redis2.8版本之前主從複製過程如下圖:

1、 slave 服務啓動,slave 會建立和master 的連接,發送sync 命令。

2、master啓動一個後臺進程將數據庫快照保存到RDB文件中

(注意: 此時如果生成RDB文件過程中存在寫數據操作會導致RDB文件和當前主redis數據不一致,所以此時master 主進程會開始收集寫命令並緩存起來。

3、master 就發送RDB文件給slave

4、slave 將文件保存到磁盤上,然後加載到內存恢復

5、master把緩存的命令轉發給slave

(注意: 後續master 收到的寫命令都會通過開始建立的連接發送給slave。)

當master 和slave 的連接斷開時slave 可以自動重新建立連接。如果master 同時收到多個slave 發來的同步連接命令,只會啓動一個進程來寫數據庫鏡像,然後發送給所有slave。

image-20200623164526963

redis2.8之前完整複製的問題:

在redis2.8之前從redis每次同步都會從主redis中複製全部的數據,如果從redis是新創建的從主redis中複製全部的數據這是沒有問題的,但是,如果當從redis停止運行,再啓動時可能只有少部分數據和主redis不同步,此時啓動redis仍然會從主redis複製全部數據,這樣的性能肯定沒有隻複製那一小部分不同步的數據高。

redis2.8以後部分複製:

從機連接主機後,會主動發起 PSYNC 命令,從機會提供 master的runid(機器標識,隨機生成的一個串) 和 offset(數據偏移量,如果offset主從不一致則說明數據不同步),主機驗證 runid 和 offset 是否有效, runid 相當於主機身份驗證碼,用來驗證從機上一次連接的主機,如果runid驗證未通過則,則進行全同步,如果驗證通過則說明曾經同步過,根據offset同步部分數據。

img

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