mysql 每日一问之 GTID 主从同步
老版本主从同步
MySQL的复制原理概述上来讲大体可以分为这三步
- 在主库上把数据更改,记录到二进制日志(Binary Log)中。
- 从库将主库上的日志复制到自己的中继日志(Relay Log)中。
- 备库读取中继日志中的事件,将其重放到备库数据之上
GTID
GTID是由UUID+TransactionId组成的,UUID是单个MySQL实例的唯一标识,在第一次启动MySQL实例时会自动生成一个server_uuid, 并且默认写入到数据目录下的auto.cnf(mysql/data/auto.cnf)文件里。TransactionId是该MySQL上执行事务的数量,随着事务数量增加而递增。这样保证了 GTID在一组复制中,全局唯一
GTID的工作原理
当从服务器连接主服务器时,把自己执行过的GTID( Executed_Gtid_Set: 即已经执行的事务编码 )以及获取到GTID( Retrieved_Gtid_Set: 即从库已经接收到主库的事务编号 )都传给主服务器。主服务器会从服务器缺少的GTID以及对应的transactionID都发送给从服务器,让从服务器补全数据。当主服务器宕机时,会找出同步数据最成功的那台conf服务器,直接将它提升为主服务器。若是强制要求某一台不是同步最成功的一台从服务器为主,会先通过change命令到最成功的那台服务器,将GTID进行补全,然后再把强制要求的那台机器提升为主。
主要数据同步机制可以分为这几步:
- master更新数据时,在事务前生产GTID,一同记录到binlog中。
- slave端的i/o线程,将变更的binlog写入到relay log中。
- sql线程从relay log中获取GTID,然后对比Slave端的binlog是否有记录。
- 如果有记录,说明该GTID的事务已经执行,slave会忽略该GTID。
- 如果没有记录,Slave会从relay log中执行该GTID事务,并记录到binlog。
- 在解析过程中,判断是否有主键,如果没有主键就使用二级索引,再没有二级索引就扫描全表
GTID的优劣势
通过上面的分析我们可以得出GTID的优势是:
- 每一个事务对应一个执行ID,一个GTID在一个服务器上只会执行一次;
- GTID是用来代替传统复制的方法,GTID复制与普通复制模式的最大不同就是不需要指定二进制文件名和位置;
- 减少手工干预和降低服务故障时间,当主机挂了之后通过软件从众多的备机中提升一台备机为主机
GTID 主从同步
x@z:/opt/soft/lib/dc/mysql-master$ vi docker-compose.yml
x@z:/opt/soft/lib/dc/mysql-master$ mkdir -p master/data master/conf
x@z:/opt/soft/lib/dc/mysql-master$ mkdir -p slave/data slave/conf
docker-compose配置
version: '3'
services:
mysql-master:
image: mysql:8.0.22
container_name: mysql-master
restart: always
volumes:
- $PWD/master/data:/var/lib/mysql
- $PWD/master/conf/my.cnf:/etc/my.cnf
ports:
- 3307:3306
environment:
MYSQL_ROOT_PASSWORD: "111111"
command: --default-authentication-plugin=mysql_native_password
mysql-slave:
image: mysql:8.0.22
container_name: mysql-slave
restart: always
volumes:
- $PWD/slave/data:/var/lib/mysql
- $PWD/slavemaster/conf/my.cnf:/etc/my.cnf
ports:
- 3308:3306
environment:
MYSQL_ROOT_PASSWORD: "111111"
command: --default-authentication-plugin=mysql_native_password
master 配置
root@86cf839898ac:/# myql -uroot -p111111
mysql> CREATE USER 'repl'@'%' IDENTIFIED BY 'repl';
Query OK, 0 rows affected (0.02 sec)
mysql> GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'repl'@'%';
Query OK, 0 rows affected (0.03 sec)
slave 配置
CHANGE MASTER TO
MASTER_HOST = 'mysql-master',
MASTER_PORT = 3306,
MASTER_USER = 'repl',
MASTER_PASSWORD = 'repl',
MASTER_AUTO_POSITION = 1;
mysql> CHANGE MASTER TO
-> MASTER_HOST = 'mysql-master',
-> MASTER_PORT = 3306,
-> MASTER_USER = 'repl',
-> MASTER_PASSWORD = 'repl',
-> MASTER_AUTO_POSITION = 1;
ERROR 1777 (HY000): CHANGE MASTER TO MASTER_AUTO_POSITION = 1 cannot be executed because @@GLOBAL.GTID_MODE = OFF.
mysql> show global variables like 'gtid_mode';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| gtid_mode | OFF |
+---------------+-------+
1 row in set (0.00 sec)
mysql> set @@GLOBAL.GTID_MODE = OFF_PERMISSIVE;
Query OK, 0 rows affected (0.01 sec)
mysql> CHANGE MASTER TO
-> MASTER_HOST = 'mysql-master',
-> MASTER_PORT = 3306,
-> MASTER_USER = 'repl',
-> MASTER_PASSWORD = 'repl',
-> MASTER_AUTO_POSITION = 1;
Query OK, 0 rows affected, 2 warnings (0.03 sec)
mysql> start slave;
Query OK, 0 rows affected, 1 warning (0.00 sec)
查看同步状态
# master
mysql> show master status;
+---------------------------+----------+--------------+------------------+-------------------------------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+---------------------------+----------+--------------+------------------+-------------------------------------------+
| replicas-mysql-bin.000004 | 1569 | | | 7b988823-ad75-11ec-9898-0242ac160002:1-10 |
+---------------------------+----------+--------------+------------------+-------------------------------------------+
1 row in set (0.00 sec)
# slave
mysql> show slave status\G;
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: mysql-master
Master_User: repl
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: replicas-mysql-bin.000004
Read_Master_Log_Pos: 1569
Relay_Log_File: 6c96cb586aec-relay-bin.000004
Relay_Log_Pos: 1802
Relay_Master_Log_File: replicas-mysql-bin.000004
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
...
Replicate_Ignore_Server_Ids:
Master_Server_Id: 100
Master_UUID: 7b988823-ad75-11ec-9898-0242ac160002
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: 7b988823-ad75-11ec-9898-0242ac160002:1-10 # slave 接收到的gtid
Executed_Gtid_Set: 7b988823-ad75-11ec-9898-0242ac160002:1-10 # master 上的gtid
Auto_Position: 1
1 row in set, 1 warning (0.01 sec)