1. 程式人生 > >MySQL高可用(一)主備同步:MySQL是如何保證主備一致的

MySQL高可用(一)主備同步:MySQL是如何保證主備一致的

主備同步,也叫主從複製,是MySQL提供的一種高可用的解決方案,保證主備資料一致性的解決方案。 在生產環境中,會有很多不可控因素,例如資料庫服務掛了。為了保證應用的高可用,資料庫也必須要是高可用的。 因此在生產環境中,都會採用主備同步。在應用的規模不大的情況下,一般會採用一主一備。 除了上面提到的資料庫服務掛了,能夠快速切換到備庫,避免應用的不可用外,採用主備同步還有以下好處: **提升資料庫的讀併發性**,大多數應用都是讀比寫要多,採用主備同步方案,當使用規模越來越大的時候,可以擴充套件備庫來提升讀能力。 **備份**,主備同步可以得到一份實時的完整的備份資料庫。 **快速恢復**,當主庫出錯了(比如誤刪表),通過備庫來快速恢復資料。對於規模很大的應用,對於資料恢復速度的容忍性很低的情況,通過配置一臺與主庫的資料快照相隔半小時的備庫,當主庫誤刪表,就可以通過備庫和binlog來快速恢復,最多等待半小時。 說了主備同步是什麼和好處,下面讓我們來了解一下主備同步是怎麼實現的。 ## 主備同步的實現原理 我們先來了解一下主備同步的原理,下面以一個update語句來介紹主庫與備庫間是如何進行同步的。 ![主備同步流程圖](https://kityminder-img.gz.bcebos.com/56b908c82863817d01b220562dbb1f2328c2e5eb) 上圖是一個update語句在節點A執行,然後同步到節點B的完整流程圖,具體步驟有: 1. 主庫接受到客戶端傳送的一條update語句,執行內部事務邏輯,同時寫binlog。 2. 備庫通過 change master 命令,設定主庫的IP、埠、使用者名稱和密碼,以及要從哪個位置開始請求 binlog。這個位置包含檔名和偏移量。 3. 在備庫上執行start slave命令,啟動兩個執行緒 io\_thread 和 sql\_thread,其中 io\_thread 負責與主機進行連線。 4. 主庫校驗完使用者名稱和密碼,按照接收到的位置去讀取binlog,發給備庫。 5. 備庫接收到binlog後,寫到本地檔案(relay log,中轉檔案)。 6. 備庫讀取中轉檔案,解析出命令,然後執行。 主備同步的工作原理其實就是一個完全備份加上二進位制日誌備份的還原。不同的是這個二進位制日誌的還原操作基本上是實時的。 備庫通過兩個執行緒來實現同步: - 一個是 I/O 執行緒,負責讀取主庫的二進位制日誌,並將其儲存為中繼日誌。 - 一個是 SQL 執行緒,負責執行中繼日誌。 從上面的流程可以看出,主備同步的關鍵是binlog,在前面的文章裡也有介紹過binlog的相關內容,感興趣的小夥伴可以點選[檢視](https://www.cnblogs.com/liang24/p/14084235.html)。 ## 常見的兩種主備切換流程 ### M-S結構 M-S結構,兩個節點,一個當主庫、一個當備庫,不允許兩個節點互換角色。 ![M-S結構](https://kityminder-img.gz.bcebos.com/eb945297d915aa45dea9a1560d413a0424715d16) 在狀態1中,客戶端的讀寫都直接訪問節點A,而節點B是A的備庫,只是將A的更新都同步過來,到本地執行。這樣可以保持節點B和A的資料是相同的。 當需要切換的時候,就切成狀態2。這時候客戶端讀寫訪問的都是節點B,而節點A是B的備庫。 ### 雙M結構 雙M結構,兩個節點,一個當主庫,一個當備庫,允許兩個節點互換角色。 ![雙M結構](https://kityminder-img.gz.bcebos.com/7cb21dca74d259b2acbe54bf48af402a57dc2eae) 對比前面的M-S結構圖,可以發現,雙M結構和M-S結構,其實區別只是多了一條線,即節點A和B之間總是互為主備關係。這樣在切換的時候就不用再修改主備關係。 ### 雙M結構的迴圈複製問題 在實際生產使用中,多數情況是使用雙M結構的。但是,雙M結構還有一個問題需要解決。 業務邏輯在節點A執行更新,會生成binlog並同步到節點B。節點B同步完成後,也會生成binlog。(log\_slave\_updates設定為on,表示備庫也會生成binlog)。 當節點A同時也是節點B的備庫時,節點B的binlog也會發送給節點A,造成迴圈複製。 解決辦法: - 設定節點的server-id,必須不同,不然不允許設定為主備結構 - 備庫在接到binlog後重放時,會記錄原記錄相同的server-id,即誰產生即為誰的。 - 每個節點在接受binlog時,會判斷server-id,如果是自己的就丟掉。 解決後的流程: 1. 業務邏輯在節點A執行更新,會生成帶有節點A的server-id的binlog。 2. 節點B接受到節點A發過來的binlog,並執行完成後,會生成帶有節點A的server-id的binlog。 3. 節點A接受到binlog後,發現是自己的,就丟掉。死迴圈就在這裡斷掉了。 ## 參考資料 - [24 | MySQL是怎麼保證主備一致的?](https://time.geekbang.org/column/articl