本文问题
- 在使用GTID的MySQL复制中,如何判断主从是否一致?
-
mysql.gtid_executed
表是哪个版本开始有的?有什么作用? - GTID在什么时候记录到
mysql.gtid_executed
表中? -
gtid_purged
是个全局变量还是会话变量?它存储了哪些内容? - 如何更改
gtid_purged
,有什么作用和限制? -
gtid_next
变量有什么作用?手动设置gtid_next
有什么注意事项? - 使用什么语句重置GTID执行历史记录,该语句都进行了哪些操作?
基于GTID的复制
在使用GTID时,每个事务都可以在原始数据库上提交和在从库应用时被识别和跟踪。这意味着当使用GTID时,不需要二进制日志的文件和位置。由于GTID复制完全基于事务,所以可以简单的确定主库和从库是否一致。只要在主库上提交的所有事务在从库上也都进行了提交,就可以保证两者之间的一致性。
GTID始终在主库和从库之间维护。这意味着可以通过检查从库应用的日志来检查事务是从哪个主库获取的。另外,一旦在指定服务器上提交了具有指定GTID的事务,这个服务器会忽略具有相同GTID的事务,因此,在主库上提交的事务在从库上最多只能应用一次,这有助于确保一致性
查看服务器应用过哪些GTID
select @@global.gtid_executed;
select * from mysql.gtid_executed;
这个语句不会显示当前正在使用的二进制日志中的GTID,只有日志刷新后才会记录到该表中。
查看哪些GTID已从服务器上删除
select @@global.gtid_purged
当删除二进制日志时,如果二进制日志中存在GTID,则会将已删除的GTID记录在gtid_purged
中
GTID的格式
GTID格式
一个GTID的格式是GTID = source_id:transaction_id
source_id
标识了事务的原始服务器,通常是主库的server_uuid
transaction_id
是按照事务在主库上提交的顺序递增的一个序列号,从1开始。
GTID集合格式
GTID集合是一个包括一个或多个或者一个范围的GTID的集合。
GTID集合可以包括多个source_id
3E11FA47-71CA-11E1-9E33-C80AA9429562:1-5
3E11FA47-71CA-11E1-9E33-C80AA9429562:1-3:11:47-49
2174B383-5441-11E8-B90A-C80AA9429562:1-3, 24DA167-0C0C-11E8-8442-00059A3C7B00:1-19
GTID和GTID集合的不同使用场景
- GTID
-
mysqlbinlog
的输出是单个GTID
- 在
Performance_schema
中关于复制状态的表中记录的是单个GTID
-
gtid_next
的值是单个GTID
-
- GTID集合
-
gtid_executed
和gtid_purged
的值是GTID
集合 -
GTID_SUBSET()
和GTID_SUBTRACT()
函数需要使用GTID
集合作为输入 -
START SALVE
的UNTIL SQL_BEFORE_GTIDS
和UNTIL SQL_AFTER_GTIDS
子句可以用来设置从库应用事务到GTID
集合的第一个GTID
,或者在应用GTID
集合的最后一个GTID
后停止。
-
mysql.gtid_executed表
MySQL在5.7版本增加了mysql.gtid_executed
表。用来记录GTID
。在MySQL5.6及以前版本,由于GTID
只存储在日志文件中,使用基于GTID
的复制必须在从库上启用log_bin
和log_slave_updates
。增加了这个表之后,GTID
的信息可以记录在表中,从而允许从库在禁用日志的情况下,使用基于GTID
的复制。
使用RESET MASTER
可以清除mysql.gtid_executed
表中的内容。
只有当gtid_mode
为ON
或者ON_PERMISSIVE
时,GTID才会存储在mysql.gtid_executed
表中。
在MySQL8.0.17版本以前,GTID
的存储取决于二进制日志是否可用:
-
log_bin=OFF
或者log_slave_updates=OFF
:服务器在执行事务的同时存储该事务的GTID
-
log_bin=ON
:当刷新二进制日志或者关闭数据库时,将之前二进制日志中的所有GTID集合写入到mysql.gtid_executed
表中。
在MySQL8.0.17版本以后:
如果仅使用InnoDB存储引擎,当log_bin=ON
时,也在执行事务的同时存储该事务的GTID
到表中
GTID在从库上的应用
- 当二进制日志数据传输到从库并且存储到从库的中继日志后,从库读取
GTID
并且将gtid_next
的系统变量设置为这个GTID
。这告诉从库下一个事务必须使用这个GTID
进行记录。gtid_next
是个会话环境 - 从库验证没有线程拥有
gtid_next
中记录的GTID
的所有权以处理事务。首先读取并且检查复制的事务的GTID,在处理事务前,从库确保具有该GTID
的事务没有被应用过,并且没有其他会话已经读取了这个GTID但是还没有进行提交关联的事务。如果有多个客户端试图同时应用同一个事务,服务器只允许其中的一个事务提交。从库上的gtid_owned
变量(@@GLOBAL.gtid_owned
)显示了当前正在使用的GTID以及它正在被哪个拥有和使用。如果GTID已经被使用,不会产生错误,并且使用自动跳过函数忽略这个事务 - 如果GTID没有被使用,从库应用这个复制事务。由于
gtid_next
已经被设置为主库分配的GTID,从库不会为这个使用生成新的GTID,而是使用gtid_next
中存储的GTID - 如果从库启用了二进制日志,GTID在事务提交时写入到二进制日志中。在刷新二进制日志或者关闭服务器时,将之前的GTID集合写入到
mysql.gtid_executed
表中 - 如果从库没有启用二进制日志,GTID直接写入到
mysql.gtid_executed
表中。MySQL将一个语句添加到事务中,以将GTID插入表中。在这种情况下,mysql.gtid_executed
表是从库应用事务的完整记录。在MySQL5.7中,对于DML语句,将GTID插入表的操作是原子的,但对于DDL语句不是原子的,如果服务器在涉及DDL语句的事务处理后意外终止,则GTID状态可能会变得不一致。在MySQL8.0后,该操作对于DDL和DML语句都是原子的 - 在从库上的复制的事务提交后,GTID马上添加到从库的
gtid_executed
系统变量中。
相关系统变量
gtid_next
默认情况下,对于在用户会话提交的新事务,服务器自动生成并分配一个新的GTID、当事务在从库中应用时,将保留源服务器分配的GTID。可以通过设置gtid_next来改变这种行为:
-
gtid_next='AUTOMATIC'
当事务提交并写入到二进制日志时,自动生成并分配一个GTID。如果由于事务回滚或者其他原因没有写入到二进制日志,则不会分配GTID。自动生成的GTID是uuid:
最小未使用的transaction_id
-
gtid_next
设置为一个有效的GTID
会将该GTID分配给事务,即使事务没有写入到二进制日志或者事务为空,也会分配这个GTID。
在通过gtid_next
指定一个GTID,并且事务提交或回滚后,需要在发出其他语句前使用SET @@SESSION.gtid_next
语句来设置下一个事务的GTID。
gtid_purged
gtid_purged
中包括了所有在服务器上已经提交的,但是已经不存在于二进制日志中的事务的集合。gtid_purged
是gtid_executed
的子集。
以下类别的GTID集合存在于gtid_purged
中:
- 在禁用二进制日志的从库上应用的复制事务的GTID集合
- 在已经删除的二进制日志中的事务的GTID集合
- 通过
SET @@GLOBAL.gtid_purged
语句添加的GTID集合
可以手动将不在二进制日志中的GTID集合添加到gtid_purged
中
在MySQL5.7中,只有当gtid_executed
为空时才能修改gtid_purged
。
在MySQL8.0中,没有这种限制
- 可以使用GTID集合替换整个
gtid_purged
的内容
新GTID集合必须包括之前已经存在与gtid_purged
中的集合,并且不能包括在gtid_executed
中但是没有删除的GTID集合,也不能包括@@global.gtid_owned
中的集合。
SET @@GLOBAL.gtid_purged = 'gtid_set'
- 也可以添加指定的GTID集合到
gtid_purged
中
SET @@GLOBAL.gtid_purged = '+gtid_set'
重置GTID执行历史记录
使用RESET MASTER
语句可以重置GTID执行历史记录,将执行以下操作:
- 将
gtid_purged
值设置为空字符串(' '
) - 将
gtid_executed
的全局值设置为空字符串 - 清空
mysql.gtid_executed
表 - 如果数据库启用了二进制日志,将会删除现有的二进制日志并且清空二进制日志索引文件。重新生成序号为1的日志文件
问题答案
- 在使用GTID的MySQL复制中,如何判断主从是否一致?
通过查看已经执行的GTID集合是否一致来进行判断
查看已经执行的GTID集合
select @@global.gtid_executed;
不能通过select * from mysql.gtid_executed
来查看的原因是因为只有二进制日志刷新后才会将gtid记录到该表中,当前正在使用的二进制日志中的事务不会记录到表中 -
mysql.gtid_executed
表是哪个版本开始有的?有什么作用?
MySQL在5.7版本增加了mysql.gtid_executed
表。用来记录GTID。
在MySQL5.6及以前版本,由于GTID只存储在日志文件中,使用基于GTID的复制必须在从库上启用log_bin
和log_slave_updates
。增加了这个表之后,GTID的信息可以记录在表中,从而允许从库在禁用日志的情况下,使用基于GTID的复制。 - GTID在什么时候记录到
mysql.gtid_executed
表中?
- 在MySQL8.0.17版本以前,GTID的存储取决于二进制日志是否可用:
-
log_bin=OFF
或者log_slave_updates=OFF
:服务器在执行事务的同时存储该事务的GTID -
log_bin=ON
:当刷新二进制日志或者关闭数据库时,将之前二进制日志中的所有GTID集合写入到mysql.gtid_executed
表中。
-
- 在MySQL8.0.17版本以后:
如果仅使用InnoDB存储引擎,当log_bin=ON
时,也在执行事务的同时存储该事务的GTID到表中
-
gtid_purged
是个全局变量还是会话变量?它存储了哪些内容?
gtid_purged
是个全局变量
gtid_purged
中包括了所有在服务器上已经提交的,但是已经不存在于二进制日志中的事务的集合。gtid_purged
是gtid_executed
的子集。
以下类别的GTID集合存在于gtid_purged
中:
1.在禁用二进制日志的从库上应用的复制事务的GTID集合
2.在已经删除的二进制日志中的事务的GTID集合
3.通过SET @@GLOBAL.gtid_purged
语句添加的GTID集合 - 如何更改
gtid_purged
,有什么作用和限制?
更新整个gtid_purged
中的集合
SET @@GLOBAL.gtid_purged = 'gtid_set'
添加指定的GTID集合到gtid_purged
中(8.0+)
SET @@GLOBAL.gtid_purged = '+gtid_set'
作用
用于在服务器上记录已应用某个GTID集合的事务,但是这些事务在二进制日志中不存在的时候。
比如说还原数据库,但是没有包含事务的相关二进制日志的时候
限制
在MySQL5.7中,只有当gtid_executed
为空时才能修改gtid_purged
。
在MySQL8.0中,没有这种限制 -
gtid_next
变量有什么作用?手动设置gtid_next
有什么注意事项?
默认情况下,对于在用户会话提交的新事务,服务器自动生成并分配一个新的GTID、当事务在从库中应用时,将保留源服务器分配的GTID。可以通过设置gtid_next
来改变这种行为:
-
gtid_next='AUTOMATIC'
当事务提交并写入到二进制日志时,自动生成并分配一个GTID。如果由于事务回滚或者其他原因没有写入到二进制日志,则不会分配GTID。 -
gtid_next
设置为一个有效的GTID
会将该GTID分配给事务,即使事务没有写入到二进制日志或者事务为空,也会分配这个GTID。
注意事项:
在通过gtid_next
指定一个GTID,并且事务提交或回滚后,需要在发出其他语句前使用SET @@SESSION.gtid_next
语句来设置下一个事务的GTID。
- 使用什么语句重置GTID执行历史记录,该语句都进行了哪些操作?
RESET MASTER
操作:
- 将
gtid_purged
值设置为空字符串(' ') - 将
gtid_executed
的全局值设置为空字符串 - 清空
mysql.gtid_executed
表 - 如果数据库启用了二进制日志,将会删除现有的二进制日志并且清空二进制日志索引文件。重新生成序号为1的日志文件
网友评论