MySQL 複製 - 性能與擴展性的基石:概述及其原理

原文: MySQL 複製 - 性能與擴展性的基石:概述及其原理

1. 複製概述

MySQL 內置的複製功能是構建基於 MySQL 的大規模、高性能應用的基礎,複製解決的基本問題是讓一臺服務器的數據與其餘服務器保持同步html

接下來,咱們將從複製概述及原理、複製的配置、常見的問題及解決方法來學習 MySQL 的複製功能。mysql

1.1 複製解決的問題

下面是複製常見的用途:sql

  • 數據分佈。Mysql 複製一般不會對帶寬形成很大壓力,但在 5.1 版本中引入的基於行的複製會比傳統的基於語句的複製模式產生更大的帶寬壓力。你能夠隨意地中止或開始複製,並在不一樣的地理位置來分佈數據備份,例如不一樣的數據中心。另外,即便在不穩定的網絡環境下,遠程複製也能夠工做。但若是將來保存很低的複製延遲,最好有一個穩定、低延遲的鏈接。
  • 負載均衡。經過 Mysql 複製,能夠將讀操做分佈到多個服務器上,實現對讀密集型應用的優化,而且很容易實現,經過簡單的代碼修改就能實現基本的負載均衡。對應小規模的應用,能夠簡單的使用 DNS 輪詢(將一個機器名指向多個 IP 地址)。
  • 備份。對於備份來講,負載是一項頗有意義的技術補充。
  • 高可用性和故障切換。負載可以幫助應用避免 Mysql 單點失敗,一個使用複製的設計良好的系統可以顯著的縮短宕機時間。
  • Mysql 升級測試。這是比較常見的作法,在更新 Mysql 版本前,先使用將要更新的版本做爲備庫,保證更新版本不會對系統形成影響。

1.2 複製是如何工做的?

在詳細介紹如何設置複製以前,讓咱們先看看 Mysql 其實是如何進行數據複製的。編程

總的來講,複製有三個步驟:緩存

  1. 在主庫上把數據更改寫入到二進制日誌(Binary Log)中(這些記錄被稱爲二進制日誌事件)。
  2. 備庫將主庫上的日誌複製到本身的中繼日誌(Relay Log)中。
  3. 備庫讀取中繼日誌中的事件,將其更改同步到備庫。

以上是複製的簡單概述,下圖描述了複製的細節:
MySQL 複製流程圖服務器

總體複製過程:網絡

  1. 在主庫上記錄二進制日誌。在每次準備提交事務完成 數據更新前,主庫將數據更新的事件記錄到二進制日誌中。Mysql 會按事務提交的順序而非每條語句的執行順序來記錄二進制日誌。在記錄二進制日誌後,主庫會告訴存儲引擎能夠提交事務了。
  2. 備庫將主庫的二進制日誌複製到其本地的中繼日誌中首先,備庫會啓動一個工做線程,稱爲 I/O 線程,I/O 線程跟主庫創建一個普通的客戶端鏈接,而後在主庫上啓動一個特殊的二進制轉儲(binlog dump)線程,這個二進制轉儲線程會讀取主庫二進制日誌中的事件。它不會對時間進行輪詢。若是該線程「追趕」上了主庫,它將進入睡眠狀態,直到主庫發送信號量通知它有新的事件產生纔會被換新,備庫 I/O 線程會將接收到的事件記錄到中繼日誌中。
  3. 備庫啓動 SQL 線程,執行最後一步。該線程從中繼日誌中讀取事件並在備庫執行,從而實現備庫數據的更新。當 SQL 線程追遇上 I/O 線程時,中繼日誌一般已經在系統緩存中,因此中繼日誌的開銷很低。SQL 線程執行的事件也能夠經過配置項來決定是否寫入自身的二進制日誌中,這對於備庫再配置備庫的常見很是有用。

這種複製架構實現了獲取事件重放事件的解耦,容許這兩個過程異步進行。也就是說 I/O 線程可以獨立於 SQL 線程以前工做。可是,這種架構也限制了複製的過程,其中最重要的一點是,在主庫上併發運行的查詢在備庫上只能串行化執行,由於只有一個 SQL 線程來重放中繼日誌中的事件。架構

不過值得高興的是,5.7 版本已經支持從庫的並行複製了。基於二進制日誌的並行複製,是在日誌內容中新增了 last_committed 和 sequence_number,分別 表示事務提交的時間和上次事務提交的編號。若是事務具備相同的時間,表示這些事務是在一組內,能夠進行並行回放。併發

2. 複製的原理

咱們已經瞭解了複製的一些基本概念,接下來咱們要更深刻的瞭解複製,看看複製到底是如何工做的,有哪些優缺點。負載均衡

2.1 基於語句的複製

在 Mysql 5.0 及以前的版本中只支持基於語句的複製(也稱爲邏輯複製)。基於語句的複製模式,主庫會記錄那些形成數據更改的 SQL 語句,當備庫讀取並重放這些事件時,實際上只是把主庫執行過的 SQL 再執行一遍。這種方式既有優勢,也有缺點。

優勢是:

  1. 實現簡單。理論上來講,只要簡單地記錄和執行 SQL 語句,就可以讓主備保持同步。
  2. 二進制日誌不會對帶寬產生較大影響。二進制日誌裏的事件更加緊湊,佔用帶寬較小。

但事實上,基於語句的方式可能並不如其看起來那麼便利,其缺點是:

  1. 主庫上的數據除了執行的語句外,可能還依賴其餘因素。當主庫使用 CURRENT_USER() 函數的語句,存儲過程和觸發器在使用基於語句的複製模式時就可能會出現問題。

2.2 基於行的複製

Mysql 5.1 開始支持基於行的複製。這種方式會將實際數據記錄在二進制日誌中。一樣的,它也有其自身的優缺點。

它的優勢是能夠更加準確的複製數據,而缺點,則是可能形成較大的開銷。好比一個工資表中有一萬個用戶,咱們把每一個用戶的工資+1000,那麼基於行的複製則要複製一萬行的內容,由此形成的開銷比較大,而基於語句的複製僅僅一條語句就能夠了。

因爲沒有哪一種模式是對全部狀況都是完美的,Mysql 就使複製模式能夠動態切換。默認狀況下使用的是基於語句的複製方式,但若是發現語句沒法被正確地複製,就切換到基於行的複製模式。還能夠根據須要來設置會話級別的變量 binlog_format,控制二進制日誌格式。

2.3 複製文件解讀

複製過程當中會使用到一些文件。前面已經介紹了二進制日誌文件中繼日誌文件,除此以外,還有其餘的文件會被用到。

  1. mysql-bin.index:當在服務器上開啓二進制日誌時,同時會生成一個和二進制日誌同名,但以 .index 做爲後綴的文件,該文件用於記錄磁盤上的二進制日誌文件。這裏的 index 並非表的索引,而是說這個文件的每一行包含了二進制文件的文件名。Mysql 依賴這個文件識別二進制日誌文件。
  2. mysql-relay-bin-index:中繼日誌的索引文件,和 mysql-bin.index 的做用相似。
  3. master.info:保存備庫鏈接主庫所須要的信息文件。格式爲純文本(每行一個值),不一樣的 Mysql 版本,記錄的信息也可能不太。此文件不能刪除,不然備庫再重啓後不能鏈接主庫。這個文件以文本的方式記錄了複製用戶的密碼,因此要注意此文件的權限控制。
  4. relay-log.info:記錄當前備庫複製的二進制日誌和中繼日誌位置文件。

使用這些文件來記錄 Mysql 複製和日誌狀態是一種很是粗糙的方式。更不幸的是,它們不是同步寫的。若是服務器斷電而且文件數據沒有被刷新到磁盤,在重啓服務器後,文件中記錄的數據多是錯誤。不過好在這些問題以及在 5.5 版本里作了改進。

2.4 發送複製事件到其它備庫

log_slave_update 選項可讓備庫編程其它服務器的主庫。在設置該選項後,Mysql 會將其執行過的事件記錄到它本身的二進制日誌中。這樣它的備庫就能夠從其日誌中檢索並執行事件。下圖闡述了這一過程:
將複製時間傳遞到更多的備庫

在這種場景下,主庫將數據更新事件寫入二進制日誌,第一個備庫提取並執行這個事件。這個時候一個事件的生命週期應該已經結束了。但因爲設置了 log_slave_updates,備庫會將這個事件寫到它本身的二進制日誌中。這樣第二個備庫就能夠從第一個備庫中,將事件提取到它的中繼日誌中並執行。

這意味着做爲源服務器的主庫能夠將其數據變化傳遞給沒有與其直接相連的備庫上。默認狀況下,這個選項是被打開的,這樣在鏈接到備庫時就不須要重啓服務器。

當第一個備庫把自主庫得到的事件寫入到其它二進制日誌中時,這個事件在備庫二進制日誌中的位置與其主庫二進制日誌中的位置幾乎確定是不相同的,可能在不一樣的日誌文件或文件內不一樣的位置。這意味着你不能假定全部擁有同一邏輯複製點的服務器擁有相同的日誌座標。

小結

  1. 複製功能是 MySQL 高擴展性的基礎,常見的讀寫分離就使用了複製。
  2. 複製使用了三個線程。master 的日誌線程,將事件寫入 binlog,slave 的 IO 線程獲取 binlog,並將其寫入 relaylog,SQL 線程重放 relaylog 日誌。
  3. 複製有基於語句複製和基於行的複製。

參考:

  1. 高性能 MySQL - 第 3 版;
相關文章
相關標籤/搜索