基于GTID的复制是从Mysql5.6开始支持的一种新的复制方式,此方式与传统基于日志的方式存在很大的差异,在原来的基于日志的复制中,从服务器连接到主服务器并告诉主服务器要从哪个二进制日志的偏移量开始执行增量同步,这时我们如果指定的日志偏移量不对,这与可能造成主从数据的不一致,而基于GTID的复制会避免。
在基于GTID的复制中,首先从服务器会告诉主服务器已经在从服务器执行完了哪些事务的GTID值,然后主库会有把所有没有在从库上执行的事务,发送到从库上进行执行,并且使用GTID的复制可以保证同一个事务只在指定的从库上执行一次,这样可以避免由于偏移量的问题造成数据不一致。
什么是GTID,也就是全局事务ID,其保证为每一个在主上提交的事务在复制集群中可以生成一个唯一的ID。
一个GITD由两部分组成的,分别是source_id 和transaction_id,GTID=source_id:transaction_id,其中source_id就是执行事务的主库的server-uuid值,server-uuid值是在mysql服务首次启动生成的,保存在数据库的数据目录中,在数据目录中有一个auto.conf文件,这个文件保存了server-uuid值(唯一的)。而事务ID则是从1开始自增的序列,表示这个事务是在主库上执行的第几个事务,Mysql会保证这个事务和GTID是一比一的关系。
配置主数据库服务器需要做的大概和传统的主从配置差不多,需要起码的在主服务器上建立复制账号,还要配置数据库日志文件的目录,这是必须的启动bin_log日志。
可以指定bin_log存放目录,而不是用数据目录,分开存储是个好习惯,特别是如果把日志和数据放在不同的磁盘分区上,这样不但可以避免日志的增长把数据磁盘分区占满,也可以提高了磁盘IO。如bin_log = /usr/local/mysql/log/mysql-bin。
优点
A:很方便的进行故障转移,因为GTID是全局唯一的标识符,所以就很简单知道哪些事务在从服务器没有执行,在多个从服务器也没必要进行多个日志偏移量配置了.
B:从库和主库的数据一致性。
缺点
A:故障处理比日志处理复杂。
B:执行语句的一些限制。
虚拟机IP:192.168.136.142(Master)、192.168.136.143(Slave)
Mysql版本:5.6(5.7的配置与5.6稍微有些不一样,如果你的Mysql版本是5.7,可以参考其他文章)
首先配置一下主服务器,编辑/etc/my.cnf
[mysqld]
port = 3306
socket = /tmp/mysql.sock
basedir = /usr/local/mysql
datadir = /data/mysql
pid-file = /data/mysql/mysql.pid
server-id = 142
log_bin = mysql-bin
bin_log = /usr/local/mysql/log/mysql-bin
binlog_format = ROW //建议row
log-slave-updates=true //在从服务器进入主服务器传入过来的修改日志所使用,在Mysql5.7之前主从架构上使用gtid模式的话,必须使用此选项,在Mysql5.7取消了,会增加系统负载。
enforce-gtid-consistency=true // 强制gtid一直性,用于保证启动gitd后事务的安全;
gtid-mode=on //开启gtid模式
master_info_repository=TABLE
relay_log_info_repository=TABLE //指定中继日志的存储方式,默认是文件,这样配置是使用了 两个表,是INNODB存储引擎,好处是当出现数据库崩溃时,利用INNODE事务引擎的特点,对这两个表进行恢复,以保证从服务器可以从正确位置恢复数据。
sync-master-info=1 //同步master_info,任何事物提交以后都必须要把事务提交以后的二进制日志事件的位置对应的文件名称,记录到master_info中,下次启动自动读取,保证数据无丢失
slave-parallel-workers=2 //设定从服务器的启动线程数,0表示不启动
binlog-checksum=CRC32 //主服务端在启动的时候要不要校验bin-log本身的校验码
master-verify-checksum=1 //都是在服务器出现故障情况下,读取对服务器有用的数据
slave-sql-verify-checksum=1
binlog-rows-query-log_events=1 //启用后,可用于在二进制日志记录事件相关信息,可降低故障排除复杂度(并非强制启动)
report-port=3306
report-host=192.168.136.142
配置完成之后别忘了重启Mysql。
查看一下master状态,多了一项。
主服务进入Mysql,命令行执行授权
grant replication client,replication slave on *.* to root@'192.168.136.%' identified by 'root123'; //ip段与账号密码
flush privileges; //刷新权限
show grants for root@'192.168.136.%';
启动配置之前,我们同样需要对从服务器进行初始化。对从服务器初始化的方法基本和基于日志点是相同的,只不过在启动了GTID模式后,在备份中所记录的就不是备份时的二进制日志文件名和偏移量了,而是记录的是备份时最后的GTID值。
查看一下有哪些数据库,退出Mysql终端,进入一个目录,把目标库备份一下,这里是testdb
mysqldump --single-transaction --master-data=2 --triggers --routines --database testdb -uroot -p > testdb.sql
备份完成之后,查看一下sql文件内容。
然后把当前sql文件拷贝到从服务器,这里使用scp命令。
scp -P22 testdb.sql [email protected]:/data/mysql/
拷贝完之后,进入从服务器Mysql终端,创建目标数据库,然后倒入到从库。
mysql -uroot -p testdb < testdb.sql
倒入成功之后,接下来配置从服务器,与主服务器配置大概一致,从服务器可以在配置文件里面添加 read_only=ON ,使从服务器只能进行读取操作,此参数对超级用户无效,并且不会影响从服务器的复制;
port = 3306
socket = /tmp/mysql.sock
basedir = /usr/local/mysql
datadir = /data/mysql
pid-file = /data/mysql/mysql.pid
user = mysql
bind-address = 0.0.0.0
server-id = 143
log_bin = mysql-bin
bin_log = /usr/local/mysql/log/mysql-bin
binlog_format = ROW //建议row
log-slave-updates=true
enforce-gtid-consistency=true
gtid-mode=on
master_info_repository=TABLE
relay_log_info_repository=TABLE //指定中继日志的存储方式,默认是文件,这样配置是使用了 两个表,是INNODB存储引擎,好处是当出现数据库崩溃时,利用INNODE事务引擎的特点,对这两个表进行恢复,以保证从服务器可以从正确位置恢复数据。
sync-master-info=1
slave-parallel-workers=2 //开启线程数,0就表示禁用线程
binlog-checksum=CRC32
master-verify-checksum=1
slave-sql-verify-checksum=1
binlog-rows-query-log_events=1
report-port=3306
report-host=192.168.136.143
read_only = on //这个参数主要保证从服务器的数据安全性
别忘了重启mysql。
然后进入mysql终端,使用change master 配置主从
change master to master_host='192.168.136.142',
master_user='root',
master_passwrd='root123',
master_auto_position=1;
start slave; //配置完成启动slave
在主数据库端查看一下
配置成功了。然后试着在主库上执行一条insert 语句,在从库上查看,OK,数据也有了
MySQL 传统的主从复制方式使用 master_log_files 和 master_log_pos 两个参数来确定复制位点。当出现复制错误时,可以设置跳过出错的事务来恢复同步,MySQL 提供了 sql_slave_skip_counter 参数来实现此功能。使用方法如下:
root@(none) >stop slave;
Query OK, 0 rows affected (0.00 sec)
root@(none) >SET GLOBAL SQL_SLAVE_SKIP_COUNTER = N; #跳过N个事务
Query OK, 0 rows affected (0.00 sec)
root@(none) >start slave;
Query OK, 0 rows affected, 1 warning (0.03 sec)
如果使用 GTID 的主从复制方式,上面这种方法并不会生效。如果有同学做过尝试,应该会收到如下报错信息。
ERROR 1858 (HY000): sql_slave_skip_counter can not be set when the server is running with @@GLOBAL.GTID_MODE = ON. Instead, for each transaction that you want to skip, generate an empty transaction with the same GTID as the transaction
在 GTID 模式下使用 sql_slave_skip_counter 参数将会引发错误:
root@(none) >stop slave;
Query OK, 0 rows affected (0.00 sec)
root@(none) >set global sql_slave_skip_counter = 1;
ERROR 1858 (HY000): sql_slave_skip_counter can not be set when the server is running with @@GLOBAL.GTID_MODE = ON. Instead, for each transaction that you want to skip, generate an empty transaction with the same GTID as the transaction
那使用 GTID 复制的数据库出现复制错误时该如何处理呢?其实上面的报错信息已经提示了解决方法:在发生错误的 GTID 事务号上插入一个空的事务,来实现跳过此复制错误的效果。
操作方法:
1 "show slave status\G" 找到发生复制错误的 GTID 事务号(示例只展示复制错误信息,其他信息省略),可以找到发生复制错误的 GTID 为:ab1b2733-2401-11e7-82fc-525400abbf4b:50
root@(none) >show slave status\G
1. row **
Last_Error: Worker 7 failed executing transaction 'ab1b2733-2401-11e7-82fc-525400abbf4b:50' at master log mysql-bin.000012, end_log_pos 156045; Could not execute Delete_rows_v1 event on table test.test2; Can't find record in 'test2', Error_code: 1032; handler error HA_ERR_KEY_NOT_FOUND; the event's master log FIRST, end_log_pos 156045
2 向上面找到的 GTID 插入一个空的事务
stop slave; # 关闭 slave 复制
SET GTID_NEXT='$GTID_NO'; # 设置 GTID_NEXT 为复制出错的 GTID_NO
begin; commit; # 向 $GTID_NO 写入空事务
SET GTID_NEXT="AUTOMATIC"; # 重新设置 GTID_NEXT 为自动获取
start slave; # 启动 slave 复制
示例:
root@(none) >stop slave;
Query OK, 0 rows affected (0.00 sec)
root@(none) >SET GTID_NEXT='ab1b2733-2401-11e7-82fc-525400abbf4b:50';
Query OK, 0 rows affected (0.00 sec)
root@(none) >begin;
Query OK, 0 rows affected (0.00 sec)
root@(none) >commit;
Query OK, 0 rows affected (0.00 sec)
root@(none) >SET GTID_NEXT="AUTOMATIC";
Query OK, 0 rows affected (0.00 sec)
root@(none) >start slave;
Query OK, 0 rows affected, 1 warning (0.03 sec)
3 重要:数据订正
主库查看gtid_purged并且记录
mysql> show global variables like '%gtid_purged%'\G
Variable_name: gtid_purged
Value: 0003be53-e103-11e7-9374-7cd30ab49ab8:1-209325833,
0a3aea84-f824-11e6-a4f1-ecf4bbd14b7c:1-226325123,
1494a77a-93ba-11e7-9b7e-6c92bf3160a3:1-113493689,
cdcb29ce-f7ad-11e5-9c99-f84abfe485f4:1-4244249,
db4186a3-f7ad-11e5-9c99-ac853daf2ee1:1-4,
fde4cefa-93b9-11e7-9b7d-6c92bf2c1761:1-131616080
在从库执行
#清除从库的主从信息
mysql> stop slave;
mysql> reset slave;
mysql> reset master;
#设置gtid_purged
mysql> set @@global.gtid_purged='0003be53-e103-11e7-9374-7cd30ab49ab8:1-209325833,
0a3aea84-f824-11e6-a4f1-ecf4bbd14b7c:1-226325123
,1494a77a-93ba-11e7-9b7e-6c92bf3160a3:1-113493689,
cdcb29ce-f7ad-11e5-9c99-f84abfe485f4:1-4244249,
db4186a3-f7ad-11e5-9c99-ac853daf2ee1:1-4,
fde4cefa-93b9-11e7-9b7d-6c92bf2c1761:1-131616080';
#重新设置主从同步
mysql> change master to master_host='ip地址',
master_port=3306,
master_user='usernamet',
master_password='password',
master_auto_position=1;
#启动从
mysql> start slave;
如果主从同步配置完成后遇到类似于错误1的错误,可以使用错误1的解决方法来解决。