MySQL主從復制原理及實踐
第1章 MySQL的主從復制介紹
MySQL的主從復制方案,和上述文件及文件系統級別同步是類似的,都是數據的傳輸。只不過MySQL無需借助第三方工具,而是其自帶的同步復制功能。另外一點,MySQL的主從復制並不是磁盤上文件直接同步,而是邏輯的binlog日誌同步到本地再應用執行的過程。
復制可以單向:M=>S,也可以是雙向M<==>M,也可以是多M換裝同步等。如果設置了鏈式級聯復制,那麽,從(slave)服務器本身除了充當從服務器外,也會同時充當其下面從服務器的主服務器。鏈式級聯復制類似A-->B-->C-->D的復制形式。
主從復制條件:
1、開啟binlog功能
2、主庫建立同步賬號
3、從庫配置master.info(change master)
4、start slave 復制開關
1.1 主從復制原理介紹
MySQL的主從復制是一個異步的復制過程(雖然一般情況下感覺是實時的),數據將從一個MySQL數據庫(Master)復制到另外一個MySQL數據庫(Slave),兩個數據庫之間實現整個主從復制的過程是由三個線程參與完成的。其中兩個線程(SQL和I/O)在Slave端,另外一個線程(I/O)在Master端。
要實現MySQL的主從復制,首先必須打開Master端的binlog記錄功能,否則就無法實現。因為整個復制過程實際上就是Slave從Master端獲取binlog日誌,然後在
[mysqld] log-bin = /data/3306/mysql-bin
1.2 MySQL主從復制原理過程詳細描述
第一步:
在Slave服務器上執行start slave命令開啟主從復制開關,開始進行主從復制。
第二步:
此時,Slave服務器的I/O線程會通過在Master上已經授權的復制用戶權限請求連接Master服務器,並請求從指定binlog日誌文件的指定位置(日誌文件名和位置就是在配置主從復制服務時執行change master命令指定的)之後開始發送binlog日誌內容。
第三步:
Master服務器接受到來自Slave服務器的
第四步:
當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 Log中I/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、主庫新建數據庫test;2、從庫刪除同步過來的數據庫test;3、主庫上再刪除數據庫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主從復制原理及實踐