1. 程式人生 > 實用技巧 >搭建MySQL主從複製及原理詳解

搭建MySQL主從複製及原理詳解

目錄

搭建MySQL主從複製及原理詳解

​ MySQL的複製有3中常見架構,分別是一主多從複製架構、多級複製架構和雙主複製架構。本片文章主要講解的是一主多從架構及其搭建過程,其它兩種有興趣的讀者可以留言。

1.複製簡述

​ MySQL從3.23版本開始提供複製的功能。複製是指將主資料庫的DDL和DML操作通過二進位制日誌傳到複製伺服器(也叫從庫)上,然後在從庫上對這些日誌重新執行(也叫重做),從而使得從庫和主庫的資料保持同步。
​ MySQL支援一臺主庫同時向多臺從庫進行復制,從庫同時也可以作為其他伺服器的主庫,實現鏈狀的複製。
​ MySQL複製的優點主要包括以下3個方面:

  1. 如果主庫出現問題,可以快速切換到從庫提供服務;
  2. 可以在從庫上執行查詢操作,降低主庫的訪問壓力;
  3. 可以在從庫上執行備份,以避免備份期間影響主庫的服務。

2.複製原理

​ (1)首先,MySQL主庫在事務提交時會把資料變更作為事件Events記錄在二進位制日誌檔案Binlog中;MySQL主庫上的sync_binlog引數控制Binlog日誌重新整理到磁碟。
​ (2)主庫推送二進位制日誌檔案Binlog中的事件到從庫的中繼日誌Relay Log,之後從庫根據中繼日誌Relay Log重做資料變更操作,通過邏輯複製以此來達到主庫和從庫的資料一致。
​ MySQL通過 3個執行緒來完成主從庫間的資料複製:其中Binlog Dump執行緒跑在主庫上, I/O執行緒和SQL執行緒跑在從庫上。當在從庫上啟動複製(START SLAVE)時,首先建立 I/O執行緒連線主庫,主庫隨後建立Binlog Dump執行緒讀取資料庫事件併發送給 I/O執行緒,I/O執行緒獲取到事件資料後更新到從庫的中繼日誌Relay Log中去,之後從庫上的SQL執行緒讀取中繼日誌Relay Log中更新的資料庫事件並應用,如下圖所示:

<img src="C:\Users\50312\AppData\Roaming\Typora\typora-user-images\image-20201207083143526.png" alt="image-202

01207083143526" style="zoom:80%;" />

3.複製涉及的各類檔案

二進位制日誌(Binlog)

​ 二進位制日誌檔案(Binlog)會把 MySQL 中的所有資料修改操作以二進位制的形式記錄到日誌檔案中,包括Create、Drop、Insert、Update、Delete操作等,但二進位制日誌檔案(Binlog)不會記錄Select操作,因為Select操作並不修改資料。
​ 二進位制日誌檔案Binlog格式有以下3種:

  • Statement:基於SQL語句級別的Binlog,每條修改資料的SQL都會儲存到Binlog裡
  • Row:基於行級別,記錄每一行資料的變化,也就是將每行資料的變化都記錄到Binlog裡面,記錄得非常詳細,但是並不記錄原始SQL;在複製的時候,並不會因為儲存過程或觸發器造成主從庫資料不一致的問題,但是記錄的日誌量較Statement格式要大得多。
  • Mixed:混合Statement和Row模式,預設情況下采用Statement模式記錄,某些情況下會切換到Row模式,例如SQL中包含與時間、使用者相關的函式等。

中繼日誌(Relay Log)

​ 中繼日誌檔案Relay Log的檔案格式、內容和二進位制日誌檔案Binlog一樣,唯一的區別在於從庫上的SQL執行緒在執行完當前中繼日誌檔案Relay Log中的事件之後,SQL執行緒會自動刪除當前中繼日誌檔案Relay Log,避免從庫上的中繼日誌檔案Relay Log佔用過多的磁碟空間。

4.搭建步驟

關閉主從機器的防火牆

# systemctl stop iptables(需要安裝iptables服務)
# systemctl stop firewalld(預設)
# systemctl disable firewalld.service(設定開啟不啟動)

主伺服器配置

第一步:修改my.cnf檔案

​ 修改主資料庫伺服器的配置檔案my.cnf,開啟BINLOG,並設定server-id的值。這兩個引數的修改需要重新啟動資料庫服務才可以生效。

[mysqld]
#啟用二進位制日誌
log-bin=mysql-bin
#伺服器唯一ID,一般取IP最後一段
server-id=136

第二步:重啟MySQL

# systemctl restart mysqld

第三步:授予Slave從機許可權

mysql> GRANT REPLICATION SLAVE ON *.* TO 'root'@'192.168.211.138'IDENTIFIED BY '123456';

第四步:重新整理許可權

FLUSH PRIVILEGES;

第五步:檢視master的狀態

mysql> show master status;
+------------------+----------+--------------+------------------+-------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000006 |      120 |              |                  |                   |
+------------------+----------+--------------+------------------+-------------------+

上圖表示,主機將從 mysql-bin.000006這個二進位制檔案的120行這個位置開始同步。

從伺服器配置

第一步:修改my.cnf檔案

[mysqld]
server-id=138

確保叢集中的各個伺服器的server-id唯一。

第二步:重啟並登入到從庫

先使用如下命令檢視從機是否在執行,是的話先停止執行

mysql> show slave status \G;
mysql> stop slave;

第三步:配置從資料庫伺服器

​ 指定複製使用者,主資料庫伺服器IP、埠以及開始執行復制的日誌檔案和位置等,具體如下:

mysql> change master to
-> master_host='master_host_name',
-> master_port='master_host_port',
-> master_user='replication_user_name',
-> master_password='replication_password',
-> master_log_file='recorded_log_file_name',
-> master_log_pos=recorded_log_position;

舉例說明如下:

mysql> change master to
    -> master_host='192.168.211.136',
    -> master_port=3306,
    -> master_user='root',
    -> master_password='123456',
    -> master_log_file='mysql-bin.000006',
    -> master_log_pos=120;

第四步:啟動slave執行緒

mysql> start slave;
Query OK, 0 rows affected (0.01 sec)

第五步:檢查從伺服器複製功能狀態

mysql> show slave status \G;
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 192.168.211.136
                  Master_User: root
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: mysql-bin.000006
          Read_Master_Log_Pos: 120
               Relay_Log_File: mysqld-relay-bin.000002
                Relay_Log_Pos: 283
        Relay_Master_Log_File: mysql-bin.000006
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
。。。。。。。省略

Slave_IO_Running: Yes 說明從庫IO執行緒已就緒。
Slave_SQL_Running: Yes 說明從庫SQL執行緒已就緒。

測試

​ 搭建成功之後,往主機中插入資料,看看從機中是否有資料

注: 如果出現複製不成功,可以使用
mysql> set global sql_slave_skip_counter =1; # 忽略一個錯誤
mysql> start slave

5.存在問題:主從延時

檢視主機處理狀態

​ 可以通過SHOW PROCESSLIST命令在主庫上檢視Binlog Dump執行緒,從BinlogDump執行緒的狀態可以看到,MySQL 的複製是主庫主動推送日誌到從庫去的,是屬於“推”日誌的方式來做同步

mysql> mysql> show processlist \g;
+----+------+-----------------------+------+-------------+-------+-----------------------------------------------------------------------+------------------+
| Id | User | Host                  | db   | Command     | Time  | State                                                                 | Info             |
+----+------+-----------------------+------+-------------+-------+-----------------------------------------------------------------------+------------------+
|  3 | root | 192.168.211.1:50147   | NULL | Sleep       | 11225 |                                                                       | NULL             |
|  6 | root | 192.168.211.138:52846 | NULL | Binlog Dump |  6174 | Master has sent all binlog to slave; waiting for binlog to be updated | NULL             |
|  7 | root | localhost             | NULL | Query       |     0 | init                                                                  | show processlist |
+----+------+-----------------------+------+-------------+-------+-----------------------------------------------------------------------+------------------+
3 rows in set (0.00 sec)

檢視從機處理狀態

​ 在從庫上通過SHOW PROCESSLIST可以看到 I/O執行緒和SQL執行緒,I/O執行緒等待主庫上的Binlog Dump執行緒傳送事件並更新到中繼日誌Relay Log,SQL執行緒讀取中繼日誌Relay Log並應用變更到資料庫:

mysql> show processlist \g;
+----+-------------+---------------------+------+---------+------+-----------------------------------------------------------------------------+------------------+
| Id | User        | Host                | db   | Command | Time | State                                                                       | Info             |
+----+-------------+---------------------+------+---------+------+-----------------------------------------------------------------------------+------------------+
|  4 | root        | 192.168.211.1:50207 | NULL | Sleep   |  572 |                                                                             | NULL             |
|  6 | system user |                     | NULL | Connect | 6343 | Waiting for master to send event                                            | NULL             |
|  7 | system user |                     | NULL | Connect | 5859 | Slave has read all relay log; waiting for the slave I/O thread to update it | NULL             |
|  9 | root        | localhost           | NULL | Query   |    0 | init                                                                        | show processlist |
+----+-------------+---------------------+------+---------+------+-----------------------------------------------------------------------------+------------------+
4 rows in set (0.00 sec)

解決方案

​ 從MySQL複製流程可以瞭解到複製是非同步進行的。所以從庫上的資料和主庫會存在一定的延時,為了減少延時,可以考慮以下幾種解決方案:

  1. 因為SQLThread和IOThread是預設單執行緒,當主機的tps(每秒事務處理數)高於從機的Thread所能
    承受範圍,則會出現從機複製延時
    解決方案: 將thread改成多執行緒模式 MySQL5.6改表,MySQL5.7改GTID
  2. 網路延時
    解決方案: 主和從在一個網內
  3. IO延時
    解決方案:slave server硬體升級
    判斷延時:
    show slave status中Seconds_Behind_Master=0則不延時