美文网首页
MySQL复制和GTID

MySQL复制和GTID

作者: 月饮沙 | 来源:发表于2020-04-07 17:57 被阅读0次

    本文问题

    1. 在使用GTID的MySQL复制中,如何判断主从是否一致?
    2. mysql.gtid_executed表是哪个版本开始有的?有什么作用?
    3. GTID在什么时候记录到mysql.gtid_executed表中?
    4. gtid_purged是个全局变量还是会话变量?它存储了哪些内容?
    5. 如何更改gtid_purged,有什么作用和限制?
    6. gtid_next变量有什么作用?手动设置gtid_next有什么注意事项?
    7. 使用什么语句重置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_executedgtid_purged的值是GTID集合
      • GTID_SUBSET()GTID_SUBTRACT()函数需要使用GTID集合作为输入
      • START SALVEUNTIL SQL_BEFORE_GTIDSUNTIL SQL_AFTER_GTIDS子句可以用来设置从库应用事务到GTID集合的第一个GTID,或者在应用GTID集合的最后一个GTID后停止。

    mysql.gtid_executed表

    MySQL在5.7版本增加了mysql.gtid_executed表。用来记录GTID。在MySQL5.6及以前版本,由于GTID只存储在日志文件中,使用基于GTID的复制必须在从库上启用log_binlog_slave_updates。增加了这个表之后,GTID的信息可以记录在表中,从而允许从库在禁用日志的情况下,使用基于GTID的复制。
    使用RESET MASTER可以清除mysql.gtid_executed表中的内容。
    只有当gtid_modeON或者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在从库上的应用

    1. 当二进制日志数据传输到从库并且存储到从库的中继日志后,从库读取GTID并且将gtid_next的系统变量设置为这个GTID。这告诉从库下一个事务必须使用这个GTID进行记录。gtid_next是个会话环境
    2. 从库验证没有线程拥有gtid_next中记录的GTID的所有权以处理事务。首先读取并且检查复制的事务的GTID,在处理事务前,从库确保具有该GTID的事务没有被应用过,并且没有其他会话已经读取了这个GTID但是还没有进行提交关联的事务。如果有多个客户端试图同时应用同一个事务,服务器只允许其中的一个事务提交。从库上的gtid_owned变量(@@GLOBAL.gtid_owned)显示了当前正在使用的GTID以及它正在被哪个拥有和使用。如果GTID已经被使用,不会产生错误,并且使用自动跳过函数忽略这个事务
    3. 如果GTID没有被使用,从库应用这个复制事务。由于gtid_next已经被设置为主库分配的GTID,从库不会为这个使用生成新的GTID,而是使用gtid_next中存储的GTID
    4. 如果从库启用了二进制日志,GTID在事务提交时写入到二进制日志中。在刷新二进制日志或者关闭服务器时,将之前的GTID集合写入到mysql.gtid_executed表中
    5. 如果从库没有启用二进制日志,GTID直接写入到mysql.gtid_executed表中。MySQL将一个语句添加到事务中,以将GTID插入表中。在这种情况下,mysql.gtid_executed表是从库应用事务的完整记录。在MySQL5.7中,对于DML语句,将GTID插入表的操作是原子的,但对于DDL语句不是原子的,如果服务器在涉及DDL语句的事务处理后意外终止,则GTID状态可能会变得不一致。在MySQL8.0后,该操作对于DDL和DML语句都是原子的
    6. 在从库上的复制的事务提交后,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_purgedgtid_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的日志文件

    问题答案

    1. 在使用GTID的MySQL复制中,如何判断主从是否一致?
      通过查看已经执行的GTID集合是否一致来进行判断
      查看已经执行的GTID集合
      select @@global.gtid_executed;
      不能通过select * from mysql.gtid_executed来查看的原因是因为只有二进制日志刷新后才会将gtid记录到该表中,当前正在使用的二进制日志中的事务不会记录到表中
    2. mysql.gtid_executed表是哪个版本开始有的?有什么作用?
      MySQL在5.7版本增加了mysql.gtid_executed表。用来记录GTID。
      在MySQL5.6及以前版本,由于GTID只存储在日志文件中,使用基于GTID的复制必须在从库上启用log_binlog_slave_updates。增加了这个表之后,GTID的信息可以记录在表中,从而允许从库在禁用日志的情况下,使用基于GTID的复制。
    3. 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到表中
    1. gtid_purged是个全局变量还是会话变量?它存储了哪些内容?
      gtid_purged是个全局变量
      gtid_purged中包括了所有在服务器上已经提交的,但是已经不存在于二进制日志中的事务的集合。gtid_purgedgtid_executed的子集。
      以下类别的GTID集合存在于gtid_purged中:
      1.在禁用二进制日志的从库上应用的复制事务的GTID集合
      2.在已经删除的二进制日志中的事务的GTID集合
      3.通过SET @@GLOBAL.gtid_purged语句添加的GTID集合
    2. 如何更改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中,没有这种限制
    3. 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。
    1. 使用什么语句重置GTID执行历史记录,该语句都进行了哪些操作?
      RESET MASTER
      操作:
    • gtid_purged值设置为空字符串(' ')
    • gtid_executed的全局值设置为空字符串
    • 清空mysql.gtid_executed
    • 如果数据库启用了二进制日志,将会删除现有的二进制日志并且清空二进制日志索引文件。重新生成序号为1的日志文件

    相关文章

      网友评论

          本文标题:MySQL复制和GTID

          本文链接:https://www.haomeiwen.com/subject/jmmhphtx.html