共计 5758 个字符,预计需要花费 15 分钟才能阅读完成。
本篇内容介绍了“怎么理解 mysql GTID 主从复制”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让丸趣 TV 小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!
一、GTID 的概述:
1、全局事物标识:global transaction identifieds。
2、GTID 事物是全局唯一性的,且一个事务对应一个 GTID。
3、一个 GTID 在一个服务器上只执行一次,避免重复执行导致数据混乱或者主从不一致。
4、GTID 用来代替 classic 的复制方法,不在使用 binlog+pos 开启复制。而是使用 master_auto_postion= 1 的方式自动匹配 GTID 断点进行复制。
5、MySQL-5.6.5 开始支持的,MySQL-5.6.10 后开始完善。
6、在传统的 slave 端,binlog 是不用开启的,但是在 GTID 中,slave 端的 binlog 是必须开启的,目的是记录执行过的 GTID(强制)。
二、GTID 的组成部分:
前面是 server_uuid:后面是一个序列号
例如:server_uuid:sequence number
7800a22c-95ae-11e4-983d-080027de205a:10
UUID:每个 mysql 实例的唯一 ID,由于会传递到 slave,所以也可以理解为源 ID。
Sequence number:在每台 MySQL 服务器上都是从 1 开始自增长的序列,一个数值对应一个事务。
三、GTID 比传统复制的优势:
1、更简单的实现 failover,不用以前那样在需要找 log_file 和 log_Pos。
2、更简单的搭建主从复制。
3、比传统复制更加安全。
4、GTID 是连续没有空洞的,因此主从库出现数据冲突时,可以用添加空事物的方式进行跳过。
四、GTID 的工作原理:
1、master 更新数据时,会在事务前产生 GTID,一同记录到 binlog 日志中。
2、slave 端的 i /o 线程将变更的 binlog,写入到本地的 relay log 中。
3、sql 线程从 relay log 中获取 GTID,然后对比 slave 端的 binlog 是否有记录。
4、如果有记录,说明该 GTID 的事务已经执行,slave 会忽略。
5、如果没有记录,slave 就会从 relay log 中执行该 GTID 的事务,并记录到 binlog。
6、在解析过程中会判断是否有主键,如果没有就用二级索引,如果没有就用全部扫描。
要点:
1、slave 在接受 master 的 binlog 时,会校验 master 的 GTID 是否已经执行过(一个服务器只能执行一次)。
2、为了保证主从数据的一致性,多线程只能同时执行一个 GTID。
六、使用 GTID 搭建 mysql 的主从复制的主要参数:
[mysqld]
#GTID:
gtid_mode=on
enforce_gtid_consistency=on
server_id=2003306 # 每天实例的 server_id 都要不一样
#binlog
log-bin=mysqlbin
log-slave-updates=1 #允许下端接入 slave
binlog_format=row # 强烈建议,其他格式可能造成数据不一致
#relay log
skip_slave_start=1
注意:建议使用 mysql-5.6.5 以上的最新版本。
(二)、启动 GTID 的两种方法:
方法一、
1、如果是在已经跑的服务器,你需要重启一下 mysql server。
2、启动之前,一定要先关闭 master 的写入,保证所有 slave 端都已经和 master 端数据保持同步。
3、所有 slave 需要加上 skip_slave_start= 1 的配置参数,避免启动后还是使用老的复制协议。
方法二、
1、如果是新搭建的服务器,直接启动就行了。
七、master-slave 搭建的注意事项:
(一)、使用 GTID 的方式,把 salve 端挂载 master 端:
1、启动以后最好不要立即执行事务,而是先 change master 上。
2、然后在执行事务,当然知不是必须的。
3、使用下面的 sql 切换 slave 到新的 master。
stop slave;
change master to
master_host = 192.168.100.200,
master_port = 3306,
master_user = abobo,
master_password=123,
master_auto_position = 1;
(二)、如果给已经运行的 GTID 的 master 端添加一个新的 slave
有两种方法:
方法一、适用于 master 也是新建不久的情况。
1、如果你的 master 所有的 binlog 还在。可以选择类似于上面的方法,安装 slave,直接 change master to 到 master 端。
2、原理是直接获取 master 所有的 GTID 并执行。
3、优点:简单方便。
4、缺点:如果 binlog 太多,数据完全同步需要时间较长,并且 master 一开始就启用了 GTUD。
方法二、适用于拥有较大数据的情况。(推荐)
1、通过 master 或者其他 slave 的备份搭建新的 slave。(看第三部分)
2、原理:获取 master 的数据和这些数据对应的 GTID 范围,然后通过 slave 设置 @@global.gtid_purged 跳过备份包含的 gtid。
3、优点:是可以避免第一种方法的不足。
4、缺点:相对来说有点复杂。
(三)、通过备份搭建新的 slave:(方法二的扩展)
两种方法:
方法一、mysqldump 的方式:
1、在备份的时候指定 –master-data=2(来保存 binlog 的文件号和位置的命令)。
2、使用 mysqldump 的命令在 dump 文件里可以看到下面两个信息:
SET @@SESSION.SQL_LOG_BIN=0;
SET @@GLOBAL.GTID_PURGED= 7800a22c-95ae-11e4-983d-080027de205a:1-8
3、将备份还原到 slave 后,使用 change master to 命令挂载 master 端。
注意:在 mysql5.6.9 以后的命令才支持这个功能。
方法二、percona Xtrabackup
1、Xtrabackup_binlog_info 文件中,包含 global.gtid_purged= XXXXXX:XXXX 的信息。
2、然后到 slave 去手工的 SET GLOBAL.GTID_PURGED= XXXXXX:XXXX。
3、恢复备份,开启 change master to 命令。
注意:如果系统运行了很久,无法找到 GTID 的编号了,可以通过上面的方式进行查找。
八、GTID 如何跳过事务冲突:
1、这个功能主要跳过事务,代替原来的 set global sql_slave_skip_counter = 1。
2、由于在这个 GTID 必须是连续的,正常情况同一个服务器产生的 GTID 是不会存在空缺的。所以不能简单的 skip 掉一个事务,只能通过注入空事物的方法替换掉一个实际操作事务。
3、注入空事物的方法:
stop slave;
set gtid_next= xxxxxxx:N
begin;commit;
set gtid_next= AUTOMAIC
start slave;
4、这里的 xxxxx:N 也就是你的 slave sql thread 报错的 GTID,或者说是你想要跳过的 GTID。
九、GTID 的参数注释:
[master] show global variables like %gtid%
1、enforce_gtid_consistency:开启 gtid 的一些安全限制(介意开启)。
2、gtid_executed:全局和 seeeion 级别都可以用。用来保存已经执行过的 GTIDs。
贴士:show master status\G; 输出结果中的 Executed_Gtid_Set 和 gitd_executed 一致。reset master 时,此值会被清空。
3、gtid_owned:全局和 session 级别都可用,全局表示所有服务器拥有 GTIDs,session 级别表示当前 client 拥有所有 GTIDs。(此功能用的少)
4、gtid_mode:是否开启 GTID 功能。
5、gtid_purged:全局参数,设置在 binlog 中,已经 purged 的 GTIDs,并且 purged 掉的 GTIDs 会包含到 gtid_executed 中。
贴士:从而导致 slave 不会再去 master 请求这些 GTIDs,并且 Executed_Gtid_Set 为空时,才可以设置此值。
6、gtid_next:这个时 session 级别的参数:
[master] show session variables like %gtid_next%
十、关于 GTID 的一些功能限制:
(一)、更新非事务引擎:
1、Case 重现:
master:对一个 innodb 表做一个多 sql 更新的事物,效果是产生一个 GTID。
slave:对应的表是 MYISAM 引擎,执行这个 GTID 的第一个语句后就会报错,因为非事务引擎一个 sql 就是一个事务。
2、错误编号:
last_Errno:1756
3、异常恢复方案:
(1)、简单的 stop slave; start slave; 就能够忽略错误。但是这个时候主从的一致性已经出现问题。需要手工的把 slave 差的数据补上。
(2)、首先将引擎调整为一样的,slave 也改为事务引擎。
(二)、不支持 create table ….select statements
1、case 重现:
master:直接执行一个 create table select * from table; 的 sql
2、报错:
error 1786
3、原理:
由于 create table …select 语句会生成两个 sql,一个是 DDL 创建表 SQL,一个是 insert into 插入数据的 sql。由于 DDL 会导致自动提交,所以这个 sql 至少需要两个 GTID,但是 GTID 模式下,只能给这个 sql 生成一个 GTID,如果强制执行会导致和上面更新非事务引擎一样的结果。
(三)、一个 sql 同事操作 innodb 引擎和 myisam 引擎:
case 重现:t1 表是 innodb,t2 表是 myisam
1、update t1,t2 set t1.id=1000,t2.id=1000 where t1.id=t2.id;
2、报错:1785
3、原理和第二个相同。
(四)、在一个 replication grouop 中,所有的 mysql 必须要统一开启或者关闭 GTID 功能。
1、case 重现:
将一个未开启 gtid 的 slave 通过原始的 binlog 和 pos 方式连接到开启 GTID 的 master。
2、报错:
The slave IO thread stops because the master has @@GLOBAL.GTID_MODE ON and this server has @@GLOBAL.GTID_MODE OFF。
(五)、在一个 replication group 中,如果开启 GTID 以后,就不再允许使用 classic 的复制方式:
1、case 重现:
将一个开启 gtid 的 slave 通过原始的 binlog 和 pos 方式连接到开启 GTID 的 master。
2、报错:
ERROR 1776(HY000):Parameters MASTER_LOG_FILE,MASTER_LOG_POS,RELAY_LOG_FILE and RELAY_LOG_POS cannot be set when MASTER_AUTO_POSITION is active。
(六)、GTID_MODE 是 not online 的:
需要重启才能生效,官方暂时不支持平滑的从 classic replication 切换到 GTID replication。
贴士:
由于 GTID 开启需要重启系统,一个复制组中所有的实例必须统一开启或者关闭 GTID, 开启 GTID 以后不能在使用 classic 复制。
问题:
也就是说在线业务必须统一关闭,然后再启动,会导致服务中断。
解决方案:
1、针对这种情况,社区有两种对应的平滑升级的方案:
一种是 booking.com 出品,这两个差别在淘宝 9 月份数据库月报里有说明,加了一个桥接的服务器,既可以运行 GTID 模式下,也可以运行 classic 模式下。
另外一种是 facebook.com 出品。所有的 slave 可以在开启 GTID 模式的情况下,可以连接到没有开启 GTID 模式的 master。
2、可以关闭一个部分,停止写操作,但是读不用,将另一部分改成 GTID 模式。
(七)、Temporary tables。
1、create temporary table 和 drop temporary table 语句一样在 GTID 环境下不支持。
如果 –enforce_gtid_consistency 参数开启,并且 autocommit=1,那么可以使用。
(八)、关于 Errant transaction
1、Errant transaction:所谓的 errant transaction 也就是没有规范的从 master 执行,而是直接从 slave 执行的事务。
2、由于 GTID 协议的原因,最开始已经提过(参见 GTID architecture)。
3、如果 slave 有 errant transaction 产生,由于 GTID 协议中的规则,很容易导致 failover 失败。主要有两种情况:
a、在 slave 上做了无用的或者临时的 errant transaction 操作,如果该 slave 升级成为 master 的话,连接到它的所有数据库都会获取到这个事务。如果一样就会产生冲突。
b、由于做了这个 errant transaction 这个事务以后,其他的 slave 还没有获取这个 errant transaction 的 GTID,需要从 master 上发同步给其他的 slave,但是主的 binlog 又被删掉了,这时将会报错。
4、总之:尽量避免产生 errant transaction。可以通过:set sql_log_bin=off 的方式在 slave 执行 sql,但是也要考虑到数据一致性。
“怎么理解 mysql GTID 主从复制”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注丸趣 TV 网站,丸趣 TV 小编将为大家输出更多高质量的实用文章!