专职DBA-MySQL基于GTID的复制 GTID(global transaction identifier)是一个在数据库上对每一个已经提交到数据库的事务的惟一编号。 GTID = server_uuid:gtid GTID复制的工做原理: (1).当主库进行数据更新时,会在事务前产生gtid号,一同记录到binlog日志中。 (2).从库端的I/O线程将变动的binlog数据,写入到本地的中继日志relay log中。 (3).从库端的SQL线程从中继日志中获取gtid号,而后对比本地的binlog查看是否有记录。若是有记录,说明该gtid的事务已经执行,此时从库会忽略。 (4).若是没有记录,则从库就会从中继日志中获取数据并执行gtid的事务,并记录到binlog中。 同一个事务在每台数据库服务器上所在的binlog名字和位置点可能都不同,自从有了gtid感受生活幸福的不要不要滴!!!由于同一个事务的gtid在全部节点上的值都是一致的。 GTID复制优势: 根据gtid号能够知道事务最初是在哪一个数据库上提交的。 gtid的存在方便了主从复制的宕机切换(failover)。 GTID复制缺点: gtid实例和非gtid实例之间不能进行复制,也就是不能混用,要么都是gtid,要么都不是。 在同一事务中更新事务表与非事务表将致使多个gtid分配给同一事务。 MySQL GTID主从复制应用实践 ---------------------------------------------------------------- 主机规划 ---------------------------------------------------------------- 数据库角色 主机名 bond0(SSH链接IP) bond1(内网通讯IP) ---------------------------------------------------------------- 主库1(master) db01 10.0.0.11 192.168.10.11 ---------------------------------------------------------------- 主库2(slave) db02 10.0.0.12 192.168.10.12 ---------------------------------------------------------------- 主库my.cnf配置文件 [root@db01 ~]# cat /data/mysql/3306/my.cnf [mysqld] # for mysql global user = mysql basedir = /usr/local/mysql datadir = /data/mysql/3306/data tmpdir = /data/mysql/3306/tmp pid_file = /data/mysql/3306/3306.pid socket = /data/mysql/3306/mysql.sock port = 3306 server_id = 113306 character-set-server = utf8 # for binlog binlog_format = row log_bin = /data/mysql/3306/logs/mysql-bin # for error log log_error = /data/mysql/3306/error.log # general log general_log = off general_log_file = /data/mysql/3306/general.log # for slow query log slow_query_log = on slow_query_log_file = /data/mysql/3306/slow.log long_query_time = 1.000000 # for gtid gtid_mode = on enforce_gtid_consistency = on # for replication # for innodb [mysql] character-set-client = utf8 #prompt ="\\u@\\h [\\d]> \" #prompt ="mysql [\\d]> \" #prompt ="Master [\\d]> \" #prompt ="Slave [\\d]> \" [root@db01 ~]# vim /etc/my.cnf [mysql] prompt ="Master [\\d]> \" 从库配置my.cnf文件 [root@db02 ~]# cat /data/mysql/3306/my.cnf [mysqld] # for mysql global user = mysql basedir = /usr/local/mysql datadir = /data/mysql/3306/data tmpdir = /data/mysql/3306/tmp pid_file = /data/mysql/3306/3306.pid socket = /data/mysql/3306/mysql.sock port = 3306 server_id = 123306 character-set-server = utf8 # for binlog binlog_format = row log_bin = /data/mysql/3306/logs/mysql-bin log_slave_updates = on # for error log log_error = /data/mysql/3306/error.log # general log general_log = off general_log_file = /data/mysql/3306/general.log # for slow query log slow_query_log = on slow_query_log_file = /data/mysql/3306/slow.log long_query_time = 1.000000 # for gtid gtid_mode = on enforce_gtid_consistency = on # for replication # for innodb [mysql] character-set-client = utf8 #prompt ="\u@\h [\d]> \" #prompt ="mysql [\d]> \" #prompt ="Master [\d]> \" #prompt ="Slave [\d]> \" [root@db02 ~]# vim /etc/my.cnf [mysql] prompt ="Slave [\d]> \" 启动主库实例 [root@db01 ~]# mysqld --defaults-file=/data/mysql/3306/my.cnf & 建立主从复制帐号 [root@db01 ~]# mysql -S /data/mysql/3306/mysql.sock -p Enter password: Master [(none)]> grant replication slave on *.* to 'rep'@'192.168.10.%' identified by '123'; Query OK, 0 rows affected, 1 warning (0.00 sec) Master [(none)]> flush privileges; Query OK, 0 rows affected (0.01 sec) Master [(none)]> reset master; Query OK, 0 rows affected (0.02 sec) Master [(none)]> show master status; +------------------+----------+--------------+------------------+-------------------+ | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set | +------------------+----------+--------------+------------------+-------------------+ | mysql-bin.000001 | 154 | | | | +------------------+----------+--------------+------------------+-------------------+ 1 row in set (0.00 sec) Master [(none)]> exit; Bye 主库进行全备 [root@db01 ~]# mysqldump -S /data/mysql/3306/mysql.sock -p -A -B -x --set-gtid-purged=off|gzip >/backup/db01_3306_$(date +%F).sql.gz Enter password: [root@db01 ~]# ls -lh /backup/ total 200K drwxr-xr-x 2 root root 29 Jul 12 03:50 conf -rw-r--r-- 1 root root 193K Jul 20 21:14 db01_3306_2019-07-20.sql.gz -rw-r--r-- 1 root root 2.2K Jul 15 05:28 eth0123.zip drwxr-xr-x 2 root root 54 Jul 12 05:39 sh drwxr-xr-x 2 root root 49 Jul 12 03:52 sql 将主库全备传到从库 [root@db01 ~]# scp -rp /backup/db01_3306_$(date +%F).sql.gz root@192.168.10.12:/backup The authenticity of host '192.168.10.12 (192.168.10.12)' can't be established. ECDSA key fingerprint is SHA256:auBeaQTHqMvqa5fgR9w9UDEho26UWpxRqc0bHUwCv/Y. ECDSA key fingerprint is MD5:fc:ad:3a:4d:d7:83:20:a5:a1:49:c6:59:39:0b:1c:e5. Are you sure you want to continue connecting (yes/no)? yes Warning: Permanently added '192.168.10.12' (ECDSA) to the list of known hosts. root@192.168.10.12's password: db01_3306_2019-07-20.sql.gz 100% 192KB 13.4MB/s 00:00 将主库全备恢复到从库 [root@db02 ~]# mysqld --defaults-file=/data/mysql/3306/my.cnf & [root@db02 ~]# cd /backup/ [root@db02 /backup]# gzip -d db01_3306_2019-07-20.sql.gz [root@db02 /backup]# ls -l total 780 drwxr-xr-x 2 root root 29 Jul 12 03:50 conf -rw-r--r-- 1 root root 792654 Jul 20 21:14 db01_3306_2019-07-20.sql -rw-r--r-- 1 root root 2243 Jul 15 05:45 eth0123.zip drwxr-xr-x 2 root root 54 Jul 12 05:39 sh drwxr-xr-x 2 root root 49 Jul 12 03:52 sql [root@db02 /backup]# mysql -S /data/mysql/3306/mysql.sock -p < db01_3306_2019-07-20.sql Enter password: 登陆从库配置复制参数 [root@db02 /backup]# mysql -S /data/mysql/3306/mysql.sock -p Enter password: change master to master_host='192.168.10.11', master_port=3306, master_user='rep', master_password='123', master_auto_position=1; Slave [(none)]> change master to -> master_host='192.168.10.11', -> master_port=3306, -> master_user='rep', -> master_password='123', -> master_auto_position=1; Query OK, 0 rows affected, 2 warnings (0.01 sec) Slave [(none)]> show slave status\G *************************** 1. row *************************** Slave_IO_State: Master_Host: 192.168.10.11 Master_User: rep Master_Port: 3306 Connect_Retry: 60 Master_Log_File: Read_Master_Log_Pos: 4 Relay_Log_File: db02-relay-bin.000001 Relay_Log_Pos: 4 Relay_Master_Log_File: Slave_IO_Running: No Slave_SQL_Running: No 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: 0 Relay_Log_Space: 154 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: NULL 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: 0 Master_UUID: Master_Info_File: /data/mysql/3306/data/master.info SQL_Delay: 0 SQL_Remaining_Delay: NULL Slave_SQL_Running_State: 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: ab0bfc5a-a681-11e9-bf5d-000c296165a9:1-123 Auto_Position: 1 Replicate_Rewrite_DB: Channel_Name: Master_TLS_Version: 1 row in set (0.00 sec) 从库启动复制 Slave [(none)]> start slave; Query OK, 0 rows affected (0.01 sec) Slave [(none)]> show slave status\G *************************** 1. row *************************** Slave_IO_State: Waiting for master to send event Master_Host: 192.168.10.11 Master_User: rep Master_Port: 3306 Connect_Retry: 60 Master_Log_File: mysql-bin.000001 Read_Master_Log_Pos: 434 Relay_Log_File: db02-relay-bin.000002 Relay_Log_Pos: 647 Relay_Master_Log_File: mysql-bin.000001 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: 434 Relay_Log_Space: 853 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: 113306 Master_UUID: 7c145945-a680-11e9-baea-000c29a14cf7 Master_Info_File: /data/mysql/3306/data/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: 7c145945-a680-11e9-baea-000c29a14cf7:1-2 Executed_Gtid_Set: 7c145945-a680-11e9-baea-000c29a14cf7:1-2, ab0bfc5a-a681-11e9-bf5d-000c296165a9:1-123 Auto_Position: 1 Replicate_Rewrite_DB: Channel_Name: Master_TLS_Version: 1 row in set (0.00 sec) [root@db02 ~]# mysql -S /data/mysql/3306/mysql.sock -p -e "show slave status\G"|egrep "Running|Seconds" Enter password: Slave_IO_Running: Yes Slave_SQL_Running: Yes Seconds_Behind_Master: 0 Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates 测试主从复制 [root@db01 ~]# mysql -S /data/mysql/3306/mysql.sock -p Enter password: Master [(none)]> show master status; +------------------+----------+--------------+------------------+------------------------------------------+ | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set | +------------------+----------+--------------+------------------+------------------------------------------+ | mysql-bin.000001 | 434 | | | 7c145945-a680-11e9-baea-000c29a14cf7:1-2 | +------------------+----------+--------------+------------------+------------------------------------------+ 1 row in set (0.00 sec) Master [(none)]> create database app01; Query OK, 1 row affected (0.00 sec) Master [(none)]> show master status; +------------------+----------+--------------+------------------+------------------------------------------+ | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set | +------------------+----------+--------------+------------------+------------------------------------------+ | mysql-bin.000001 | 596 | | | 7c145945-a680-11e9-baea-000c29a14cf7:1-3 | +------------------+----------+--------------+------------------+------------------------------------------+ 1 row in set (0.00 sec) 查看从库端复制状况 Slave [(none)]> show master status; +------------------+----------+--------------+------------------+--------------------------------------------------------------------------------------+ | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set | +------------------+----------+--------------+------------------+--------------------------------------------------------------------------------------+ | mysql-bin.000006 | 775111 | | | 7c145945-a680-11e9-baea-000c29a14cf7:1-3, ab0bfc5a-a681-11e9-bf5d-000c296165a9:1-123 | +------------------+----------+--------------+------------------+--------------------------------------------------------------------------------------+ 1 row in set (0.00 sec) Slave [(none)]> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | app01 | | mysql | | performance_schema | | sys | +--------------------+ 5 rows in set (0.01 sec) gtid如何跳过事务冲突 传统复制跳过事务作法:set global sql_slave_skip_counter = 1; gtid模式采用注入空事务的方法,来跳过事务冲突: stop slave; set gtid_next='xxx:n'; begin;commit; set gtid_next='aotumatic'; start slave; 测试案例: Slave [(none)]> create database app02; Query OK, 1 row affected (0.01 sec) Slave [(none)]> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | app01 | | app02 | | mysql | | performance_schema | | sys | +--------------------+ 6 rows in set (0.00 sec) Slave [(none)]> show master status; +------------------+----------+--------------+------------------+--------------------------------------------------------------------------------------+ | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set | +------------------+----------+--------------+------------------+--------------------------------------------------------------------------------------+ | mysql-bin.000006 | 775273 | | | 7c145945-a680-11e9-baea-000c29a14cf7:1-3, ab0bfc5a-a681-11e9-bf5d-000c296165a9:1-124 | +------------------+----------+--------------+------------------+--------------------------------------------------------------------------------------+ 1 row in set (0.00 sec) Master [(none)]> create database app02; Query OK, 1 row affected (0.01 sec) Master [(none)]> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | app01 | | app02 | | mysql | | performance_schema | | sys | +--------------------+ 6 rows in set (0.00 sec) Master [(none)]> show master status; +------------------+----------+--------------+------------------+------------------------------------------+ | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set | +------------------+----------+--------------+------------------+------------------------------------------+ | mysql-bin.000001 | 758 | | | 7c145945-a680-11e9-baea-000c29a14cf7:1-4 | +------------------+----------+--------------+------------------+------------------------------------------+ 1 row in set (0.00 sec) 从库已经出了问题 Slave [(none)]> show slave status\G *************************** 1. row *************************** Slave_IO_State: Waiting for master to send event Master_Host: 192.168.10.11 Master_User: rep Master_Port: 3306 Connect_Retry: 60 Master_Log_File: mysql-bin.000001 Read_Master_Log_Pos: 758 Relay_Log_File: db02-relay-bin.000002 Relay_Log_Pos: 809 Relay_Master_Log_File: mysql-bin.000001 Slave_IO_Running: Yes Slave_SQL_Running: No Replicate_Do_DB: Replicate_Ignore_DB: Replicate_Do_Table: Replicate_Ignore_Table: Replicate_Wild_Do_Table: Replicate_Wild_Ignore_Table: Last_Errno: 1007 Last_Error: Error 'Can't create database 'app02'; database exists' on query. Default database: 'app02'. Query: 'create database app02' Skip_Counter: 0 Exec_Master_Log_Pos: 596 Relay_Log_Space: 1177 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: NULL Master_SSL_Verify_Server_Cert: No Last_IO_Errno: 0 Last_IO_Error: Last_SQL_Errno: 1007 Last_SQL_Error: Error 'Can't create database 'app02'; database exists' on query. Default database: 'app02'. Query: 'create database app02' Replicate_Ignore_Server_Ids: Master_Server_Id: 113306 Master_UUID: 7c145945-a680-11e9-baea-000c29a14cf7 Master_Info_File: /data/mysql/3306/data/master.info SQL_Delay: 0 SQL_Remaining_Delay: NULL Slave_SQL_Running_State: Master_Retry_Count: 86400 Master_Bind: Last_IO_Error_Timestamp: Last_SQL_Error_Timestamp: 190720 21:45:26 Master_SSL_Crl: Master_SSL_Crlpath: Retrieved_Gtid_Set: 7c145945-a680-11e9-baea-000c29a14cf7:1-4 Executed_Gtid_Set: 7c145945-a680-11e9-baea-000c29a14cf7:1-3, ab0bfc5a-a681-11e9-bf5d-000c296165a9:1-124 Auto_Position: 1 Replicate_Rewrite_DB: Channel_Name: Master_TLS_Version: 1 row in set (0.00 sec) 从库故障解决 Slave [(none)]> stop slave; Query OK, 0 rows affected (0.01 sec) Slave [(none)]> set gtid_next='7c145945-a680-11e9-baea-000c29a14cf7:4'; Query OK, 0 rows affected (0.00 sec) 这是Retrieved_Gtid_Set: 7c145945-a680-11e9-baea-000c29a14cf7:1-4里的最大事务号 执行注入一个空事务 Slave [(none)]> begin;commit; Query OK, 0 rows affected (0.00 sec) Query OK, 0 rows affected (0.01 sec) 自动比较gtid使复制继续进行 Slave [(none)]> set gtid_next='automatic'; Query OK, 0 rows affected (0.00 sec) 开启复制 Slave [(none)]> start slave; Query OK, 0 rows affected (0.01 sec) Slave [(none)]> show slave status\G *************************** 1. row *************************** Slave_IO_State: Waiting for master to send event Master_Host: 192.168.10.11 Master_User: rep Master_Port: 3306 Connect_Retry: 60 Master_Log_File: mysql-bin.000001 Read_Master_Log_Pos: 758 Relay_Log_File: db02-relay-bin.000003 Relay_Log_Pos: 454 Relay_Master_Log_File: mysql-bin.000001 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: 758 Relay_Log_Space: 1477 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: 113306 Master_UUID: 7c145945-a680-11e9-baea-000c29a14cf7 Master_Info_File: /data/mysql/3306/data/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: 7c145945-a680-11e9-baea-000c29a14cf7:1-4 Executed_Gtid_Set: 7c145945-a680-11e9-baea-000c29a14cf7:1-4, ab0bfc5a-a681-11e9-bf5d-000c296165a9:1-124 Auto_Position: 1 Replicate_Rewrite_DB: Channel_Name: Master_TLS_Version: 1 row in set (0.00 sec) Slave [(none)]> exit; Bye [root@db02 ~]# mysql -S /data/mysql/3306/mysql.sock -p -e "show slave status\G"|egrep "Running|Seconds" Enter password: Slave_IO_Running: Yes Slave_SQL_Running: Yes Seconds_Behind_Master: 0 Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates