環境介紹:
CentOS 7.5
Mysql 5.7.29
Mysql主服務器:192.168.2.128
Mysql從服務器:192.168.2.129
Mysql主從同步原理:
當master服務器上的數據發生改變時(增、刪、改),則將其改變寫入二進制binlog日誌中;slave服務器會在一定時間間隔內對master二進制日誌進行探測其是否發生改變,如果發生改變,則開啓一個I/O 線程請求master二進制事件,同時主節點爲每個I/O線程啓動一個dump線程,用於向其發送二進制事件,並保存至從庫本地的中繼日誌中,從庫(從節點)將啓動SQL線程從中繼日誌中讀取二進制日誌,在本地重放,使得其數據和主節點的保持一致,最後IO線程和SQL線程將進入睡眠狀態,等待下一次被喚醒。
注意幾點:
1.master將操作語句記錄到binlog日誌中,然後授予slave遠程連接的權限(master一定要開啓binlog二進制日誌功能;通常爲了數據安全考慮,slave也開啓binlog功能)。
2.slave開啓兩個線程:IO線程和SQL線程。其中:IO線程負責讀取master的binlog內容到中繼日誌relay log裏;SQL線程負責從relay log日誌裏讀出binlog內容,並更新到slave的數據庫裏,這樣就能保證slave數據和 master數據保持一致了。
3.Mysql主從複製至少需要兩個Mysql的服務,當然Mysql服務可以分佈在不同的服務器上,也可以在一臺服務器上啓動多個服務。
4.Mysql主從複製最好確保master和slave服務器上的Mysql版本相同(如果不能滿足版本一致,那麼要保證master主節點的版本低於slave從節點的版本)
5.master和slave兩節點間時間需同步。
如上圖所示:
Mysql複製過程的第一部分就是master記錄二進制日誌。在每個事務更新數據完成之前,master在二日誌記錄這些改變。MySQL將事務串行的寫入二進制日誌,即使事務中的語句都是交叉執行的。在事件寫入二進制日誌完成後,master通知存儲引擎提交事務。
第二部分就是slave將master的binary log拷貝到它自己的中繼日誌。首先,slave開始一個工作線程——I/O線程。I/O線程在master上打開一個普通的連接,然後開始binlog dump process。Binlog dump process從master的二進制日誌中讀取事件,如果已經跟上master,它會睡眠並等待master產生新的事件。I/O線程將這些事件寫入中繼日誌。
SQL slave thread(SQL從線程)處理該過程的最後一步。SQL線程從中繼日誌讀取事件,並重放其中的事件而更新slave的數據,使其與master中的數據一致。只要該線程與I/O線程保持一致,中繼日誌通常會位於OS的緩存中,所以中繼日誌的開銷很小。
此外,在master中也有一個工作線程:和其它MySQL的連接一樣,slave在master中打開一個連接也會使得master開始一個線程。複製過程有一個很重要的限制——複製在slave上是串行化的,也就是說master上的並行更新操作不能在slave上並行操作。
構建主從同步:
主從同步介紹
-實現數據自動同步的服務結構
-主服務器: 接受客戶端訪問連接
-從服務器: 自動同步主服務器數據
-
Master(主庫)
-啓用binlog日誌
-
Slave(從庫)
-Slave_IO線程:複製master主機binlog日誌文件裏的SQL命令到本機的relay-log文件裏。
-Slave_SQL線程:執行本機relay-log文件裏的SQL語句,實現與Master數據一致。
構建思路
-
配置主庫
-啓用binlog日誌、授權用戶、查看 binlog日誌信息
-
配置從服務器
-確保與主服務器數據一致。
-設置server_id、指定主庫信息、啓動slave程序
配置Mysql主服務器
1.修改主配置文件
-啓用binlog日誌並重啓服務
[root@localhost ~]# vim /etc/my.cnf
[mysqld]
log-bin=db128 //啓用binlog日誌,指定日誌名以db128開頭
server_id=128 //指定服務器ID號
...
[root@localhost ~]# systemctl restart mysqld
[root@localhost ~]# ls /var/lib/mysql/db128.*
/var/lib/mysql/db128.000001 /var/lib/mysql/db128.index
2.授權用戶
-用戶權限爲 replication slave
-用戶名自定義
-客戶端地址允許從庫連接
-密碼自定義
注意:
replication slave
權限代表: 允許slave主機通過此用戶連接master以便建立主從複製關係。
[root@localhost ~]# mysql -uroot -p123qqq...A
...
Server version: 5.7.29-log MySQL Community Server (GPL)
...
mysql> grant replication slave on *.* to mysqluser@"%" identified by "123qqq...A";
//爲主數據庫授權用戶mysqluser,權限爲replication、slave,允許客戶端地址爲所有主機,允許訪問所有庫所有表*.*,授權用戶密碼爲123qqq...A
3.查看日誌信息
[root@localhost ~]# mysql -uroot -p123qqq...A
...
Server version: 5.7.29-log MySQL Community Server (GPL)
...
mysql> show master status; //查看binlog記錄日誌信息的偏移量position
+--------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+--------------+----------+--------------+------------------+-------------------+
| db128.000001 | 704787 | | | |
+--------------+----------+--------------+------------------+-------------------+
配置從服務器
1.修改主配置文件
-指定server_id,不允許與主庫的server_id值相同
[root@test2 ~]# vim /etc/my.cnf
[mysqld]
server_id=129
...
[root@test2 ~]# systemctl restart mysqld
2.確保與主庫數據一致
-在主庫上備份數據,備份文件拷貝給從庫
-在從庫上使用備份文件恢復數據
-從庫查看備份數據對應的binlog日誌信息
主數據庫操作:
--master-data
: 在備份文件中添加這次備份的數據對應的binlog日誌名以及備份後數據的節點編號(偏移量),以便從庫同步數據時,可以知道從哪個節點開始同步數據,保證主庫與從庫數據完全一致.
[root@localhost ~]# mysqldump -uroot -p123qqq...A --master-data test > /root/test.sql
//在主庫上備份數據庫test,並且記錄當前備份數據對應的binlog日誌信息,備份文件名爲test.sql
[root@localhost ~]# ls test.sql
test.sql
[root@localhost ~]# scp test.sql [email protected]:/root/
從數據庫操作:
[root@test2 ~]# ls test.sql
test.sql
[root@test2 ~]# mysql -uroot -p123qqq...A;
mysql> create database test; //從庫上必須有需要恢復的庫,因爲要恢復test庫,所以先創建空庫test
[root@test2 ~]# mysql -uroot -p123qqq...A test < /root/test.sql
[root@test2 ~]# mysql -uroot -p123qqq...A;
mysql> use test;
+----------------+
| Tables_in_test |
+----------------+
| lss |
| money |
+----------------+
3.指定主庫信息
命令格式:
change master to
master_host=“主庫IP地址”,
master_user=“用戶名”,
master_password=“密碼”,
master_log_file=“binlog日誌文件名”,
master_log_poss=偏移量;
主數據庫查看binlog日誌名及偏移量:
[root@localhost ~]# mysql -uroot -p123qqq...A
...
mysql> show master status; //主庫查看binlog記錄日誌信息的日誌名及偏移量
+--------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+--------------+----------+--------------+------------------+-------------------+
| db128.000001 | 2261338 | | | |
+--------------+----------+--------------+------------------+-------------------+
從庫指定主庫信息:
[root@test2 ~]# mysql -uroot -p123qqq...A;
...
mysql> show slave status;
Empty set (0.00 sec)
mysql> change master to
-> master_host="192.168.2.128", //指定主庫IP地址
-> master_user="mysqluser", //主庫授權用戶
-> master_password="123qqq...A", //授權用戶的密碼
-> master_log_file="db128.000001", //主庫binlog日誌文件名
-> master_log_pos=2261338; //備份文件的日誌偏移量
Query OK, 0 rows affected, 2 warnings (0.02 sec)
mysql> start slave; //啓動slave進程
注意:
1.指定的master信息會自動保存到/var/lib/mysql/master.info文件中。
2.若要更改指定的主庫信息,需先執行stop slave
,修改完成後在執行start slave
。
4.查看slave狀態
-確定IO線程、SQL線程都是Yes狀態
報錯解決:
mysql> show slave status\G;
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 192.168.2.128 //主庫IP地址
Master_User: mysqluser
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: db128.000002
Read_Master_Log_Pos: 452757169
Relay_Log_File: test2-relay-bin.000002
Relay_Log_Pos: 3205508
Relay_Master_Log_File: db128.000002
Slave_IO_Running: Yes //IO線程已運行
Slave_SQL_Running: Yes //SQL線程已運行
Replicate_Do_DB:
Replicate_Ignore_DB:
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: 452757169
Relay_Log_Space: 3205715
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: 128
Master_UUID: e46c9961-5780-11ea-bf2f-000c128a8b6b
Master_Info_File: /var/lib/mysql/master.info
SQL_Delay: 0
SQL_Remaining_Delay: NULL
Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates
Master_Retry_Count: 86400
Master_Bind:
Last_IO_Error_Timestamp:
Last_SQL_Error_Timestamp:
Master_SSL_Crl:
Master_SSL_Crlpath:
Retrieved_Gtid_Set:
Executed_Gtid_Set:
Auto_Position: 0
Replicate_Rewrite_DB:
Channel_Name:
Master_TLS_Version:
1 row in set (0.00 sec)
5.相關文件
-存放在從庫數據庫目錄下
master.info //主庫信息
relay-log.info //中繼日誌信息
主機名-relay-bin.xxxx //中繼日誌
主機名-relay-bin.index //索引文件
查看從庫服務器數據庫目錄下配置從庫時生成的4種文件
[root@test2 ~]# ls /var/lib/mysql
...
test2-relay-bin.index master.info relay-log.info
test2-relay-bin.000001 test2-relay-bin.000002
驗證主從同步效果
主數據庫操作:
在主數據庫服務器中創建一個新表test並賦值,再去從服務器上查看數據是否同步。
[root@localhost ~]# mysql -uroot -p123qqq...A
mysql: [Warning] Using a password on the comm
...
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| db1 |
| mysql |
| performance_schema |
| sys |
| test |
| zabbix |
+--------------------+
mysql> use test;
mysql> show tables;
+----------------+
| Tables_in_test |
+----------------+
| money |
+----------------+
mysql> create table test(name varchar(25),city varchar(30),age int);
mysql> show tables;
+----------------+
| Tables_in_test |
+----------------+
| money |
| test |
+----------------+
mysql> insert into test.test values("mysql","china",11);
mysql> select * from test.test;
+-------+-------+------+
| name | city | age |
+-------+-------+------+
| mysql | china | 11 |
+-------+-------+------+
從數據庫操作:
查看主服務器上新增的數據是否已經同步到從服務器上。
[root@test2 ~]# mysql -uroot -p123qqq...A
...
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| db1 |
| mysql |
| performance_schema |
| sys |
| test |
| zabbix |
+--------------------+
mysql> use test;
mysql> show tables;
+----------------+
| Tables_in_test |
+----------------+
| money |
| test |
+----------------+
mysql> select * from test.test;
+-------+-------+------+
| name | city | age |
+-------+-------+------+
| mysql | china | 11 |
+-------+-------+------+
可以看到我們在主數據庫服務器上新增的數據已經成功同步到從服務器上了。
延伸:
MySql主從同步的延遲問題(如何產生):
主庫針對寫操作,順序寫binlog日誌,從庫單線程去主庫順序讀”寫操作的binlog”,從庫取到binlog在本地原樣執行(隨機寫),來保證主從數據邏輯上一致。mysql的主從複製都是單線程的操作,主庫對所有增、刪、改產生binlog日誌,binlog是順序寫,所以效率很高,slave的Slave_IO_Running線程到主庫取日誌,效率比較高,下一步,問題來了,slave的Slave_SQL_Running線程將主庫的增、刪、改操作在slave實施。增、刪、改的IO操作是隨機的,不是順序的,成本高很多,還可能與slave上的其他查詢操作產生lock爭用,由於Slave_SQL_Running也是單線程的,所以一個增、刪、改操作卡住了,需要執行10分鐘,那麼所有之後的增、刪、改操作會等待這個增、刪、改操作執行完纔會繼續執行,這就導致了延時。(主庫是多進程,從庫單進程(回放relaylog),所以在高併發時,會出現延遲。)
MySQL主從同步延遲怎麼解決?
把主從同步配置爲異步模式 ,保證至少有1臺數據庫服務器與主服務器數據一致。