GTID主從復制
GTID是對傳統(tǒng)基于binary log的復制進行了增強,在binary log復制方式中,我們必須手動跟蹤主服務器的日志名稱和位置;但在GTID工作方式下面,我們無需跟蹤這兩個值,取而代之的是由MySQL自動跟蹤它們,并使用GTID來標記哪些事務已經(jīng)被處理,哪些還沒有被處理。GTID的一個優(yōu)點是:相同GTID的事務不會被重復處理,好處是可以最大限度地確保數(shù)據(jù)的一致性。
想了解更多gtid和binlog:http://www.itdecent.cn/p/63efedc95822
根據(jù)GTID搭建MySQL主從
比較喜歡docker,所以這次環(huán)境搭建也是用Docker部署
1、使用docker-compose部署兩個mysql
version: '3.6'
services:
master:
image: mysql:8.0.25
restart: always
container_name: mysql-master
environment:
TZ: Asia/Shanghai
MYSQL_ROOT_PASSWORD: root
command:
--default-authentication-plugin=mysql_native_password
--explicit_defaults_for_timestamp=true
--lower_case_table_names=1
--max_allowed_packet=128M
--sql-mode="STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ERROR_FOR_DIVISION_BY_ZERO"
ports:
- 3306:3306
slaver:
image: mysql:8.0.25
restart: always
container_name: mysql-slaver
environment:
TZ: Asia/Shanghai
MYSQL_ROOT_PASSWORD: root
command:
--default-authentication-plugin=mysql_native_password
--explicit_defaults_for_timestamp=true
--lower_case_table_names=1
--max_allowed_packet=128M
--sql-mode="STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ERROR_FOR_DIVISION_BY_ZERO"
ports:
- 3307:3306
#Are you trying to mount a directory onto a file or vice-versa
#docker 掛載只能掛載目錄,不能掛載文件,如果掛載的是文件,則docker會把他當成一個目錄,對于掛載的文件需要先創(chuàng)建
#mysql8默認加密方式cahing_sha2_password,舊版navicate不支持,可以使用mysql5.7的加密方式mysql_native_password
#也可以在mysql中執(zhí)行
#ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY 'password'; #修改加密規(guī)則
#ALTER USER 'root'@'%' IDENTIFIED BY 'password' PASSWORD EXPIRE NEVER; #更新一下用戶的密碼
#FLUSH PRIVILEGES; #刷新權限 。%表示遠程連接
2、修改配置文件
master數(shù)據(jù)庫
# 進入MySQL容器
~ docker exec -it mysql-master bash
# 編輯mysql配置文件
cat >> /etc/mysql/my.cnf << EOF
#GTID:
server_id=1 #服務器id
gtid_mode=on #開啟gtid模式
enforce_gtid_consistency=on #強制gtid一致性,開啟后對于特定create table不被支持
#binlog
log_bin=master-binlog
log-slave-updates=1
binlog_format=row #強烈建議,其他格式可能造成數(shù)據(jù)不一致
#relay log
skip_slave_start=1
max_connect_errors=1000
#default_authentication_plugin = 'mysql_native_password'
# 結束
EOF
slave數(shù)據(jù)庫
# 進入MySQL容器
~ docker exec -it mysql-slaver bash
# 編輯mysql配置文件
cat >> /etc/mysql/my.cnf << EOF
#GTID:
gtid_mode=on
enforce_gtid_consistency=on
server_id=2
#binlog
log-bin=slave-binlog
log-slave-updates=1
binlog_format=row #強烈建議,其他格式可能造成數(shù)據(jù)不一致
*#relay log*
skip_slave_start=1
EOF
3、搭建主從復制
主庫執(zhí)行
# 進入數(shù)據(jù)庫
mysql -uroot -proot;
# 創(chuàng)建有復制權限的賬號
create user 'repl'@'%' identified by 'repl';
grant replication slave,replication client on *.* to 'repl'@'%';
# 刷新權限
flush privileges;
從庫執(zhí)行
# 使用前面創(chuàng)建的賬號連接主數(shù)據(jù)庫測試下
# docker中同意網(wǎng)絡中可以只用容器名代替ip,docker會使用自己的dns解析
mysql -urepl -prepl -hmysql-slave -P 3306
# 進入數(shù)據(jù)庫
mysql -uroot -proot;
# 從庫連接主數(shù)據(jù)庫
CHANGE MASTER TO
MASTER_HOST='mysql-master',
master_user='repl',
master_password='repl',
master_port=3306,
MASTER_AUTO_POSITION = 1;
# 啟動從庫進程
start slave;
查看從庫啟動狀態(tài),從數(shù)據(jù)庫執(zhí)行 show slave status\G
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 192.168.56.101
Master_User: repl
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: master-binlog.000002
Read_Master_Log_Pos: 1135
Relay_Log_File: mysql-103-relay-bin.000002
Relay_Log_Pos: 1357
Relay_Master_Log_File: master-binlog.000002
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
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: 1135
Relay_Log_Space: 1569
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: 135
Master_UUID: 1c8f7f48-4a7c-11ea-ab18-0800278ffd3d
Master_Info_File: mysql.slave_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: 1c8f7f48-4a7c-11ea-ab18-0800278ffd3d:1-4
Executed_Gtid_Set: 1c8f7f48-4a7c-11ea-ab18-0800278ffd3d:1-4,
846de782-4a7c-11ea-95ab-080027e75c4d:1
Auto_Position: 1
Replicate_Rewrite_DB:
Channel_Name:
Master_TLS_Version:
Master_public_key_path:
Get_master_public_key: 0
1 row in set (0.00 sec)
Slave_IO_Running是Yes狀態(tài),Slave_SQL_Running是Yes狀態(tài)則表示成功
查看主從數(shù)據(jù)庫binlog日志復制情況 show master status\G;
*************************** 1. row ***************************
File: master-binlog.000001
Position: 475696
Binlog_Do_DB:
Binlog_Ignore_DB:
Executed_Gtid_Set: f0c7abf2-f548-11eb-a45d-0242ac190002:1-1128
1 row in set (0.00 sec)
*************************** 1. row ***************************
File: slave-binlog.000001
Position: 475696
Binlog_Do_DB:
Binlog_Ignore_DB:
Executed_Gtid_Set: f0c7abf2-f548-11eb-a45d-0242ac190002:1-1128
1 row in set (0.00 sec)
正常情況下兩邊binlog日志pos是相同的
4、主從不一致解決
方法一:忽略錯誤
# 從數(shù)據(jù)庫關閉復制
stop slave;
# 表示跳過一步錯誤,后面的數(shù)字可變
set global sql_slave_skip_counter =1;
start slave;
# 查看數(shù)據(jù)庫情況
show slave status\G;
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
則正常
方法二:重新做主從,完全同步
1.先進入主庫,進行鎖表,防止數(shù)據(jù)寫入
使用命令:
mysql> flush tables with read lock;
注意:該處是鎖定為只讀狀態(tài),語句不區(qū)分大小寫
2.進行數(shù)據(jù)備份
#把數(shù)據(jù)備份到mysql.bak.sql文件
[root@server01 mysql]#mysqldump -uroot -proot -hmysql-master > mysql.bak.sql
這里注意一點:數(shù)據(jù)庫備份一定要定期進行,可以用shell腳本或者python腳本,都比較方便,確保數(shù)據(jù)萬無一失
3.查看master 狀態(tài)
mysql> show master status;
4.把mysql備份文件傳到從庫機器,進行數(shù)據(jù)恢復
5.停止從庫的狀態(tài)
mysql> stop slave;
6.然后到從庫執(zhí)行mysql命令,導入數(shù)據(jù)備份
mysql> source /mysql.bak.sql
7.設置從庫同步,注意該處的同步點,就是主庫show master status信息里的| File| Position兩項
#關閉自動pos
mysql> change master to master_auto_position=0;
# 同步主從數(shù)據(jù)庫pos
mysql> change master to master_host = 'mysql-master', master_user = 'repl', master_port=3306, master_password='repl', master_log_file = 'mysql-master.000001', master_log_pos=411148;
# 開啟自動pos
mysql> change master to master_auto_position=1;
8.重新開啟從同步
mysql> start slave;
9.查看同步狀態(tài)
mysql> show slave status\G 查看:
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
好了,同步完成啦。
10.同步完成
unlock tables;