MySQL之GTID复制
mysql事务
为什么数据库需要事务?
- 你表弟向你借500元,你打开APP、爽快的给他转账了,你的卡余额提示少了500
- 你给表弟发了个微信,说,钱打过去了
- 你表弟说:没收到啊哥,你别骗我行吗
- 你钱扣少了,你表弟缺没收到钱,这事办的?咋整
讲道理应该是这样
- 超哥发起转账,转给表弟
- 超哥卡里少了500元
- 表弟卡里多了500元
这三步骤、必然不得出问题,上面的案例,就是这三步发生了问题!
如果有事务
、就不会发生这样的事
事务就是
这三件事、三个动作,是一根绳上的蚂蚱,要么都成功,要么都失败
转账要么到表弟账户、要么就转不出去、回到自己卡里
事务的ACID特性
TRANSACTION 事务
Atomicity原子性
原子性强调转账的三个步骤要么成功、要么失败
在一个事务中的所有SQL语句,要么全部执行成功,要么全部失败,即使成功的SQL语句也会被撤销,回到执行之前的状态。
Consistency一致性
一致性是指数据库从一个状态、变为另一个状态
事务开始前、与结束后,数据库的完整性约束没有被破坏。
例如转账,无论成功、或者失败、这500不会多、也不会少
要么超哥卡里扣了500元、表弟多了500元
要么超哥转账失败500元未动、表弟一毛钱也没拿到
这个总和永远是500元,不多也不少
Isolation隔离性
隔离性指的是每个读写事务对其他的事务操作,都是相互隔离不受影响的。
例如同是工商银行
- 超哥转账操作不会影响到小猪佩奇的转账操作
Durability持久性
事务一旦提交后,结果就是永久性生效。
超哥转账500给了表弟,表弟也收到钱了,这件事就结束了,真实生效了。
事务的实现
更多高级mysql知识,超哥后期会再补充
GTID是什么
从 MySQL 5.6.5 开始新增了一种基于 GTID 的复制方式。
通过 GTID 保证了每个在主库上提交的事务在集群中有一个唯一的ID。
这种方式强化了数据库的主备一致性,故障恢复以及容错能力。
在原来基于二进制日志的复制中,从库需要告知主库要从哪个偏移量进行增量同步,如果指定错误会造成数据的遗漏,从而造成数据的不一致。
借助GTID,在发生主备切换的情况下,MySQL的其它从库可以自动在新主库上找到正确的复制位置,这大大简化了复杂复制拓扑下集群的维护
,也减少了人为设置复制位置发生误操作的风险。
另外,基于GTID的复制可以忽略已经执行过的事务,减少了数据发生不一致的风险。
GTID长啥样
GTID (Global Transaction ID) 是对于一个已提交事务的编号,并且是一个全局唯一的编号。
GTID 实际上 是由 UUID+TID 组成的。
其中 UUID 是一个 MySQL 实例的唯一标识。
TID 代表了该实例上已经提交的事务数量,并且随着事务提交单调递增。下面是一个GTID的具体形式:
形式语法
GTID = source_id :transaction_id
具体结果
2E11FA47-61CA-11E1-9E33-C70AA9429562:28
在上面的定义中,每一个GTID均代表一个数据库的事务,等号右边的source_id表示执行事务的源服务器主库的uuid(也就是server_uuid)
而transaction_id是一个从1开始的自增的序列号,表示在这个主库上执行的第n个事务。
只要保证每台数据库的server_uuid全局唯一,以及每台数据库生成的transaction_id自身唯一,就能保证GTID的全局唯一性。
server_uuid是什么
还记得以前我们在my.cnf中配置了一个参数
server_id=5
并且超哥要求master、slave的server_id必须唯一
为什么换成server_uuid
MySQL 5.6用128位的server_uuid代替了原本32位的server_id的大部分功能。
原因很简单,server_id依赖于my.cnf的手工配置,有可能会产生冲突,而自动产生128位uuid的算法可以保证所有的MySQL uuid都不会发生冲突。
在进行首次启动时,MySQL会自动生成一个server_uuid,并且保存到数据库目录下的auto.cnf文件里,这个文件目前存在的唯一目的就是保存server_uuid。
在MySQL再次启动时其会读取auto.cnf文件,继续使用上次生成的server_uuid。
使用GTID
GTID复制原理流程
-
master进行数据更新时、在事务前产生GTID号、一起记录到binlog日志。
-
slave的I/O线程将变更的binlog数据,写入到本地中继日志
relay_log
-
slave的SQL线程从中继日志中获取
GTID
号,和本地的binlog对比查看是否有记录
- 有记录,说明该GTID事务已执行,slave数据库会忽略
-
如果没有记录,slave数据库从
relay_log中继日志
中获取数据,且执行该GTID的事务,记录到binlog中
根据GTID号就可以知道事务最初是在哪个数据库上提交的
有了GTID号、可以方便主从复制的故障切换
主从故障切换
如图、在没有GTID以前,主从复制的故障切换
- master-A宕机,需要将应用程序切换到master-B
- slave-C得和master-B建立新的复制关系
只需要在slave-C上执行新的change master to xxx ,指定master-B即可
问题是,同一个事务、在每台服务器上的binlog名字和位置点、可能都是不一样的
比如执行一条SQL,创建了一个新数据库,执行了一个事务,在master-A机器的binlog中数据位置如下
mysql> show master status
-> ;
+------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000003 | 557 | | | |
+------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)
但是可能在机器master-B中的bin中,同一个SQL执行后,binlog数据位置可能是
mysql> show master status
-> ;
+------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------