自mysql 5.6.5起,引入了一种基于全局事务标识符(gtid)的复制方法。gtid确保了在集群中每个提交到主库的事务都有一个唯一的标识符。这种方式强化了数据库的主备一致性,故障恢复以及容错能力。
gtid是什么gtid (global transaction id) 是对于一个已提交事务的编号,并且是一个全局唯一的编号。 gtid实际上是由uuid+tid 组成的。其中uuid是一个 mysql实例的唯一标识。tid的值随着每个提交的事务单调递增,记录了该实例上已经提交的事务数量。
下面是一个gtid的具体形式:3e11fa47-71ca-11e1-9e33-c80aa9429562:23,冒号分割前边为uuid,后边为tid。
gtid集合可以包含来自多个mysql实例的事务,它们之间用逗号分隔。
多个事务序号的范围区间若来自同一mysql实例,则应以冒号分隔各组范围。例如:e6954592-8dba-11e6-af0e-fa163e1cf111:1-5:11-18,e6954592-8dba-11e6-af0e-fa163e1cf3f2:1-27。
gtid改进有哪些在原来基于二进制日志的复制中,从库需要告知主库要从哪个偏移量进行增量同步,如果指定错误会造成数据的遗漏,从而造成数据的不一致。借助gtid,在发生主备切换的情况下,mysql的其它从库可以自动在新主库上找到正确的复制位置,这大大简化了复杂复制拓扑下集群的维护,也减少了人为设置复制位置发生误操作的风险。使用基于gtid的复制可以排除已执行的事务,从而降低数据不一致性的风险。
主库基于gtid set可以准确的知道从库缺少哪些数据,不会多给从库数据,也不会少给,避免网络带宽浪费。
mysql主从结构在一主一从情况下对于gtid来说就没有优势了,而对于2台主以上的结构优势异常明显,可以在数据不丢失的情况下切换新主。
注意:在构建主从复制之前,在一台将成为主的实例上进行一些操作(如数据清理等),通过gtid复制,这些在主从成立之前的操作也会被复制到从服务器上,引起复制失败。也就是说通过gtid复制都是从最先开始的事务日志开始,即使这些操作在复制之前执行。比如在server1上执行一些drop、delete的清理操作,接着在server2上执行change的操作,会使得server2也进行server1的清理操作。
gtid的工作原理当一个事务在主库端执行并提交时,产生gtid,一同记录到binlog日志中。
binlog传输到slave,并存储到slave的relaylog后,读取这个gtid的这个值设置gtid_next变量,即告诉slave,下一个要执行的gtid值。
sql线程从relay log中获取gtid,然后对比slave端的binlog是否有该gtid。
如果有记录,说明该gtid的事务已经执行,slave会忽略。
如果没有记录,slave就会执行该gtid事务,并记录该gtid到自身的binlog,在读取执行事务前会先检查其他session持有该gtid,确保不被重复执行。
一主一从gtid复制的搭建主机规划:
master:docker,端口3312
slave:docker,端口3313
master的配置配置文件my.cnf内容如下:
$ cat /home/mysql/docker-data/3313/conf/my.cnf# for advice on how to change settings please see# http://dev.mysql.com/doc/refman/5.7/en/server-configuration-defaults.html[mysqld]## remove leading # and set to the amount of ram for the most important data# cache in mysql. start at 70% of total ram for dedicated server, else 10%.# innodb_buffer_pool_size = 128m## remove leading # to turn on a very important data integrity option: logging# changes to the binary log between backups.# log_bin## remove leading # to set options mainly useful for reporting servers.# the server defaults are faster for transactions and fast selects.# adjust sizes as needed, experiment to find the optimal values.# join_buffer_size = 128m# sort_buffer_size = 2m# read_rnd_buffer_size = 2m#datadir=/home/mysql/docker-data/3307/data#socket=/home/mysql/docker-data/3307/mysql.sockcharacter_set_server=utf8init_connect='set names utf8'# disabling symbolic-links is recommended to prevent assorted security riskssymbolic-links=0#log-error=/home/mysql/docker-data/3307/logs/mysqld.log#pid-file=/home/mysql/docker-data/3307/mysqld.pidlower_case_table_names=1server-id=1403311log-bin=mysql-binbinlog-format=rowauto_increment_increment=1auto_increment_offset=1# 开启gtidgtid_mode=onenforce-gtid-consistency=true#rpl_semi_sync_master_enabled=1#rpl_semi_sync_master_timeout=10000
创建docker实例:
$ docker run --name mysql3312 -p 3312:3306 --privileged=true -ti -e mysql_root_password=root -e mysql_database=order -e mysql_user=user -e mysql_password=pass -v /home/mysql/docker-data/3312/conf:/etc/mysql/conf.d -v /home/mysql/docker-data/3312/data/:/var/lib/mysql -v /home/mysql/docker-data/3312/logs/:/var/log/mysql -d mysql:5.7
添加用于复制的用户并授权:
mysql> grant replication slave,file,replication client on *.* to 'repluser'@'%' identified by '123456';query ok, 0 rows affected, 1 warning (0.01 sec)mysql> flush privileges;query ok, 0 rows affected (0.01 sec)
slave的配置配置文件my.cnf内容与master一致,注意修改server-id,保持唯一。
创建docker实例:
$ docker run --name mysql3313 -p 3313:3306 --privileged=true -ti -e mysql_root_password=root -e mysql_database=order -e mysql_user=user -e mysql_password=pass -v /home/mysql/docker-data/3313/conf:/etc/mysql/conf.d -v /home/mysql/docker-data/3313/data/:/var/lib/mysql -v /home/mysql/docker-data/3313/logs/:/var/log/mysql -d mysql:5.7
开启gtid同步:
mysql> change master to master_host='172.23.252.98',master_port=3310,master_user='repluser',master_password='123456',master_auto_position=1;query ok, 0 rows affected, 2 warnings (0.02 sec)mysql> start slave;query ok, 0 rows affected (0.02 sec)
查看状态:
mysql> show master status;+------------------+----------+--------------+------------------+----------------------------------------+| file | position | binlog_do_db | binlog_ignore_db | executed_gtid_set |+------------------+----------+--------------+------------------+----------------------------------------+| mysql-bin.000008 | 154 | | | cd2eaa0a-7a59-11ec-b3b4-0242ac110002:1 |+------------------+----------+--------------+------------------+----------------------------------------+1 row in set (0.00 sec)mysql> show slave status\g;*************************** 1. row *************************** slave_io_state: waiting for master to send event master_host: 172.23.252.98 master_user: repluser master_port: 3312 connect_retry: 60 master_log_file: mysql-bin.000006 read_master_log_pos: 419 relay_log_file: 5dfbef024732-relay-bin.000003 relay_log_pos: 632 relay_master_log_file: mysql-bin.000006 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: 419 relay_log_space: 846 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: 0master_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: 1403311 master_uuid: cd2eaa0a-7a59-11ec-b3b4-0242ac110002 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: cd2eaa0a-7a59-11ec-b3b4-0242ac110002:1 executed_gtid_set: cd2eaa0a-7a59-11ec-b3b4-0242ac110002:1 auto_position: 1 replicate_rewrite_db: channel_name: master_tls_version:1 row in set (0.00 sec)
在master.order表插入数据:
mysql> insert into t_order values(4,"v");
发现数据已经同步至slave:
mysql> select * from order.t_order;+------+------+| id | name |+------+------+| 4 | v |+------+------+3 rows in set (0.00 sec)
先停止slave,再在master.order表插入数据:
mysql> insert into t_order values(5,"x");
然后再启动slave,发现数据已自动同步:
mysql> stop slave;query ok, 0 rows affected (0.01 sec)mysql> select * from order.t_order;+------+------+| id | name |+------+------+| 4 | v |+------+------+3 rows in set (0.00 sec)mysql> start slave;query ok, 0 rows affected (0.02 sec)mysql> select * from order.t_order;+------+------+| id | name |+------+------+| 4 | v || 5 | x |+------+------+4 rows in set (0.00 sec)
遇到的问题在slave服务器show slave status:
fatal error: the slave i/o thread stops because master and slave have equal mysql server uuids; these uuids must be different for replication to work.
首先检查master和slave的server_id是否一致,如果一致去修改my.cnf文件中的server_id字段:
mysql> show variables like 'server_id';
然后排查master和slave的uuid是否一致:
mysql> show variables like '%uuid%';
如果uuid一致去修改data目录下的auto.cnf文件,拷贝整个data目录,把auto.cnf文件也拷贝过来了,里面记录了数据库的uuid,每个库的uuid应该是不一样的。
以上就是mysql的gtid复制怎么应用的详细内容。