1. 程式人生 > >MySQL主從復制原理及實踐

MySQL主從復制原理及實踐

MySQL 主從復制 原理 實踐


第1章 MySQL的主從復制介紹

MySQL的主從復制方案,和上述文件及文件系統級別同步是類似的,都是數據的傳輸。只不過MySQL無需借助第三方工具,而是其自帶的同步復制功能。另外一點,MySQL的主從復制並不是磁盤上文件直接同步,而是邏輯的binlog日誌同步到本地再應用執行的過程。

復制可以單向:M=>S,也可以是雙向M<==>M,也可以是多M換裝同步等。如果設置了鏈式級聯復制,那麽,從(slave)服務器本身除了充當從服務器外,也會同時充當其下面從服務器的主服務器。鏈式級聯復制類似A-->B-->C-->D的復制形式。

主從復制條件:

1、開啟binlog功能

2、主庫建立同步賬號

3、從庫配置master.infochange master

4、start slave 復制開關

1.1 主從復制原理介紹

MySQL的主從復制是一個異步的復制過程(雖然一般情況下感覺是實時的),數據將從一個MySQL數據庫(Master)復制到另外一個MySQL數據庫(Slave),兩個數據庫之間實現整個主從復制的過程是由三個線程參與完成的。其中兩個線程SQLI/O)在Slave,另外一個線程(I/O)在Master

要實現MySQL的主從復制,首先必須打開Master端的binlog記錄功能,否則就無法實現。因為整個復制過程實際上就是SlaveMaster端獲取binlog日誌,然後在

Slave上以相同順序執行獲取的binlog日誌中記錄的各種SQL操作。

[mysqld]
log-bin = /data/3306/mysql-bin

1.2 MySQL主從復制原理過程詳細描述

第一步:

Slave服務器上執行start slave命令開啟主從復制開關,開始進行主從復制。

第二步:

此時,Slave服務器的I/O線程會通過在Master上已經授權的復制用戶權限請求連接Master服務器,並請求從指定binlog日誌文件的指定位置(日誌文件名和位置就是在配置主從復制服務時執行change master命令指定的)之後開始發送binlog日誌內容。

第三步:

Master服務器接受到來自Slave服務器的

I/O線程請求後,其上負責復制的I/O線程會根據Slave服務器的I/O線程請求的信息分批讀取指定binlog日誌文件指定位置之後的binlog日誌信息,然後返回給SlaveI/O線程。返回的信息中除了binlog日誌內容外,還有在Master服務器段記錄的新的binlog文件名稱,以及在新的binlog中的下一個指定更新位置。

第四步:

Slave服務器I/O線程獲取到Master服務器上I/O線程發送的日誌內容、日誌文件及位置點後,會將binlog日誌內容依次寫到Slave端自身的Relay Log(即中繼日誌)文件(MySQL-relay-bin.xxxxxx)的最末端,並將新的binlog文件名和位置記錄到master-info文件中,以便下一次讀取Master端新binlog日誌能夠告訴Master服務器從新binlog日誌的指定文件及位置開始請求新的binlog日誌內容。

第五步:

Slave服務器段的SQL線程會實時檢測本地的Relay LogI/O線程新增加的日誌內容,然後及時地把Relay Log文件中的內容解析成SQL語句,並在自身的Slave服務器上按解析SQL語句的位置順序執行應用這些SQL語句,並在relay-log.info中記錄當前應用中繼日誌的文件名及位置點。

第2章 主從復制步驟案例

2.1 開啟主庫binlog功能

[root@localhost ~]# grep log-bin /data/3306/my.cnf
log-bin = /data/3306/mysql-bin

2.2 確保所有實例server-id不同

[root@localhost ~]# grep server-id /data/330{6..7}/my.cnf
/data/3306/my.cnf:server-id = 1
/data/3307/my.cnf:server-id = 3

2.3 主庫授權復制的用戶rep

mysql> grant replication slave on *.* to 'rep'@'10.0.0.%' identified by '123456';
Query OK, 0 rows affected (0.00 sec)
 
mysql> flush privileges;
Query OK, 0 rows affected (0.01 sec)

2.4 主庫導出備

q 對主數據庫鎖表

mysql> flush table with read lock;
Query OK, 0 rows affected (0.00 sec)

註:鎖表之後窗口不能退出!!再開一個窗口登錄。

q 查看binlog文件及位置點(--master-data=2

mysql> show master status;
+------------------+----------+--------------+------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+----------+--------------+------------------+
| mysql-bin.000010 |     5218 |              |                  |
+------------------+----------+--------------+------------------+
1 row in set (0.00 sec)

q 新開一個shell窗口導出全備數據

[root@localhost backup]# mysqldump -uroot -p123456 -S /data/3306/mysql.sock -A -B --events |gzip> /service/backup/rep_bak_$(date +%F).sql.gz
[root@localhost backup]# ll /service/backup/
total 144
-rw-r--r-- 1 root root 145138 Feb  6 01:04 rep_bak_2018-02-06.sql.gz

q 解鎖,開放用戶寫入

mysql> unlock table;
Query OK, 0 rows affected (0.00 sec)

2.5 從庫確保server-id不同

[root@localhost ~]# grep server-id /data/3307/my.cnf
server-id = 3

2.6 主庫全備導入從庫

[root@localhost backup]# mysql -uroot -p123456 -S /data/3307/mysql.sock < rep_bak_2018-02-06.sql
[root@localhost backup]# mysql -uroot -p123456 -S /data/3307/mysql.sock -e "show databases;"
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| test               |
| test_dbk           |
+--------------------+

2.7 從庫找位置點,配置master.info

在上面的show master info得到的位置信息。

mysql-bin.000010 |     5218

從庫連接主庫的配置如下:

CHANGE MASTER TO
MASTER_HOST='10.0.0.16',
MASTER_PORT=3306,
MASTER_USER='rep',
MASTER_PASSWORD='123456',
MASTER_LOG_FILE='mysql-bin.000010',
MASTER_LOG_POS=4547;

登錄備庫,執行如上指令:

[root@localhost 3307]# mysql -uroot -p123456 -S /data/3307/mysql.sock
mysql> CHANGE MASTER TO
    -> MASTER_HOST='10.0.0.15',
    -> MASTER_PORT=3306,
    -> MASTER_USER='rep',
    -> MASTER_PASSWORD='123456',
    -> MASTER_LOG_FILE='mysql-bin.000010',
    -> MASTER_LOG_POS=5218;
Query OK, 0 rows affected (0.03 sec)
 
mysql>

註:1、默認情況下是沒有master.info文件的。在運行了如上命令之後,會在備庫的數據目錄/data/3307/data/下面生成一個master.info文件!

2、如果change錯誤,可以使用reset sleav all,再次重新設置!!

2.8 開啟從庫備份開關

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

2.9 查看從庫同步狀態

mysql> show slave status\G
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 10.0.0.15
                  Master_User: rep
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: mysql-bin.000010
          Read_Master_Log_Pos: 536031
               Relay_Log_File: relay-log.000002
                Relay_Log_Pos: 531066
        Relay_Master_Log_File: mysql-bin.000010
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes              #<==看到有這兩個線程在的時候基本就成功了。
              Replicate_Do_DB:
          Replicate_Ignore_DB: mysql
           Replicate_Do_Table:
       Replicate_Ignore_Table:
      Replicate_Wild_Do_Table:
  Replicate_Wild_Ignore_Table:
                   Last_Errno: 0
                   Last_Error:
                 Skip_Counter: 0
          Exec_Master_Log_Pos: 536031
              Relay_Log_Space: 531216
              Until_Condition: None
               Until_Log_File:
                Until_Log_Pos: 0
           Master_SSL_Allowed: No
           Master_SSL_CA_File:
           Master_SSL_CA_Path:
              Master_SSL_Cert:
            Master_SSL_Cipher:
               Master_SSL_Key:
        Seconds_Behind_Master: 0        #<==查看是否有延遲
Master_SSL_Verify_Server_Cert: No
                Last_IO_Errno: 0
                Last_IO_Error:
               Last_SQL_Errno: 0
               Last_SQL_Error:
  Replicate_Ignore_Server_Ids:
             Master_Server_Id: 1
1 row in set (0.00 sec)

q Slave_IO_Running: Yes,這個是I/O線程狀態,I/O線程負責從從庫去主庫讀取binlog日誌,並寫入到從庫的中繼日誌中,狀態為Yes表示I/O線程正常工作。

q Slave_SQL_Running: Yes,這個是SQL線程狀態,SQL線程負責讀取中繼日誌(relay-log)中的數據並轉換為SQL語句應用到從數據庫中,狀態為Yes表示I/O線程正常工作。

q Seconds_Behind_Master: 0,這個是在復制過程中,從庫比主庫延遲的秒數,這個參數很重要,但還有更準確地判斷主從延遲的方法:在主庫寫時間戳,然後從庫讀取時間戳和當前數據庫的時間進行比較,從而認定是否延遲。

2.10 查看主庫線程狀態

使用show processlist;命令可以查看mysql的線程狀態:

mysql> show processlist;
+----+------+-----------------+------+-------------+------+-----------------------------------------------------------------------+------------------+
| Id | User | Host            | db   | Command     | Time | State                                                                 | Info             |
+----+------+-----------------+------+-------------+------+-----------------------------------------------------------------------+------------------+
| 57 | root | localhost       | NULL | Query       |    0 | NULL                                                                  | show processlist |
| 61 | rep  | 10.0.0.16:34487 | NULL | Binlog Dump |  347 | Master has sent all binlog to slave; waiting for binlog to be updated | NULL             |
+----+------+-----------------+------+-------------+------+-----------------------------------------------------------------------+------------------+
2 rows in set (0.00 sec)

線程狀態說明:

主庫I/O線程工作狀態

解釋說明

Sending binlog event to slave

線程已經從二進制binlog日誌讀取了一個事件並且正將它發送到從服務器。

Finished reading one binlog; switching to next binlog

線程已經讀完二進制binlog日誌文件,並且正打開下一個要發送到從服務器的binlog日誌文件。

Has sent all binlog to slave; waiting for binlog to be updated

線程已經從binlog日誌讀取所有更新並已經發送到了從數據庫服務器。線程現在為空閑狀態,等待由主服務器上二進制binlog日誌中的新事件更新。

Waiting to finalize termination

線程停止時發生的一個很簡單的狀態。

第3章 主從復制故障解決辦法

故障再現步驟:1、主庫新建數據庫test2、從庫刪除同步過來的數據庫test3、主庫上再刪除數據庫test。簡單 執行如上步驟,則在從庫就會出現復制故障問題:

show slave status:報錯;且show slave status\G:

            Slave_IO_Running: Yes
            Slave_SQL_Running: No
        Seconds_Behind_Master: NULL
Last_Errno: 1008
Last_SQL_Error: Error 'Can't drop database 'test'; database doesn't exist' on query. Default database: 'test'. Query: 'drop database test'

q 解決方法1

stop slave;                             #<==臨時停止同步開關
set global sql_slave_skip_counter =1;   #<==將同步指針向下移動一個,可多次重復操作
start slave;                            #<==開啟同步開關

q 解決方法2

根據忽略的錯誤號事先在配置文件中配置,跳過指定的不影響業務數據的錯誤,例如:

grep slave-skip /data/3306/my.cnf
slave-skip-errors = 1032,1062,1007,1008        #<==可忽略的錯誤號自行設置

1007:數據庫已存在,創建數據庫失敗

1008:數據庫不存在,刪除數據庫失敗

1032:記錄不存在

1062:字段值重復,入庫失敗




MySQL主從復制原理及實踐