搭建MySQL主從復制及原理詳解
MySQL的復制有3中常見架構,分別是一主多從復制架構、多級復制架構和雙主復制架構。本片文章主要講解的是一主多從架構及其搭建過程,其它兩種有興趣的讀者可以留言。
1.復制簡述
MySQL從3.23版本開始提供復制的功能。復制是指將主數據庫的DDL和DML操作通過二進制日志傳到復制服務器(也叫從庫)上,然后在從庫上對這些日志重新執行(也叫重做),從而使得從庫和主庫的數據保持同步。
MySQL支持一台主庫同時向多台從庫進行復制,從庫同時也可以作為其他服務器的主庫,實現鏈狀的復制。
MySQL復制的優點主要包括以下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)
