Mysql GDIT的原理总结

GDIT的用法

从 MYSQL 的主从复制讲起

在Mysql中, 我们部署一个数据库的时候往往会有多个服务器, 我们称之为服务器的拓朴结构. 在主从复制(Replication)环境中, 通常主服务器(Master)负责处理写操作以及事务的生成与提交. 主服务器会将对服务器的操作记录到binlog中, 当事务开始执行的时候, MYSQL会在内存中暂存事务的操作, 这些操作不会写入binlog中, 只有事务完成所有操作并提交后, MySQL会将该事务的所有变更记录写入binlog.

在主从复制的数据库拓扑结构中, 主服务器(Master)写入binlog, 从服务器(Slave)根据主服务器记录的binlog重放事务, 也就说对主服务器所作的操作都在从服务器上回放一遍.
下图是MYSQL主从服务器复制的原理:

  1. 对主服务器提交的一个事务, 在事务开始执行时会生成事务的全局ID, 也就是 GDIT
  2. 事务执行完之后, 事务commit之后, 会将事务的操作写入binlog文件中, 格式为SQL语言.
  3. 主服务器(Master)的logdump Thread线程会不断地将数据从主服务器发送方到从服务器(Slave).
  4. 从服务器(Slave)的 I/O thread 线程会将收到的binlog信息写入到中继日志Relay Log文件中.
  5. 从数据库端(Slave)的SQL线程从中继日志中获取GTID号, 然后对比从数据库本地的Binlog查看其是否有记录. 如果有记录, 则说明该GTID的事务已经执行, 此时从数据库会忽略.
  6. 如果没有记录, 则从数据库就会从中继日志中获取数据并执行该GTID的事务, 并记录到binlog中. 根据GTID号可以知道事务最初是在哪个数据库上提交的, GTID的存在方便了主从复制的宕机切换(failover).

GDIT 介绍

MYSQL官方网站对GDIT的介绍如下:

A global transaction identifier (GTID) is a unique identifier created and associated with each transaction committed on the server of origin (the source). This identifier is unique not only to the server on which it originated, but is unique across all servers in a given replication topology.

所以简单来说GDIT可以看做是事务的唯一 identifier, 在数据库的拓扑结构中仍然保持唯一.
当一个事务开始执行时, 主服务器会给这个事务分配一个GDIT, 只有这个事务Commit之后, 该事务的信息才会被写入到binlog中, 此后, 该事务的GDIT被锁定, 在主数据库与从数据库中都不会改变. GDIT分配时保连续递增, 但是实际最后Commit的事务的GDIT不一定连续, 这是因为事务在执行过程中可能会Drop, 或者回滚.
不会分配GDIT的情况:

  1. 一个事务没有被写入binlog文件, 例如读事务, 或者该事务被筛选掉了.

主从复制的复制事务使用与主服务器上相同的GDIT. 从服务器(Slave) 通常不会写binlog,虽然它有自己的binlog文件, 即使会写binlog, 从服务器仍然会使用和主服务器相同的GDIT.

GDIT的组成

一个事务的GDIT由两部分组成, 格式为 GTID = source_id:transaction_id;
其中 source_id通常为主服务器的ID, transaction_id 实际就是按照序列生成的事务ID. transaction_id 的结构以是 long long类型的, 最大支持 \(2^{64}-1\). 当快要到达这个极限时, mysql会先发出告警, 到达极限后, 会报错.

MySQL的GDIT也支持TAG, 此时, GDIT由三部分组成, 如下:

GTID = source_id:tag:transaction_id

GTID Sets的用法

GDIT Sets 是由一个或多个GTID组成的集合, 可以包含单个GTID或一系列GTID的范围.
GDIT Set有多种作用, 常见的两个 GDIT 集合是: gtid_executed 和 gtid_purged 系统变量,

  1. gtid_executed 系统变量存储了在主服务器上已经成功执行并提交了的所有事务的GDIT的集合.
  2. gtid_purged 表示已经从binlog中清除了的 GDIT的集合, 通常是在清理 binlog 时.

在数据库主从复制的时候, START REPLICA 选项也会与GDIT 集合有关. START_REPLICA有两个选项:

  1. UNTIL SQL_BEFORE_GTIDS: 让从服务器在重放binlog中的事务时, 从UNTIL SQL_BEFORE_GTIDS 开始执行事务.
  2. UNTIL SQL_AFTER_GTIDS: 主从复制重放binlog中的事务的时候, 最多只会重放 UNTIL SQL_AFTER_GTIDS 之前的事务.

mysql.gtid_executed Table

我们知道gtid_executed 存储主服务器中已经成功执行并且Commit的事务, 这张表在Mysql数据库安装, 或者升级的时候建立. 创建这张表的语句类似下面这样:

CREATE TABLE gtid_executed (
  source_uuid CHAR(36) NOT NULL,
  interval_start BIGINT NOT NULL,
  interval_end BIGINT NOT NULL,
  gtid_tag CHAR(32) NOT NULL,
  PRIMARY KEY (source_uuid, gtid_tag, interval_start)
);

这张表存储的时Mysql的系统数据, 作为系统的表, 并不建议修改.

gtid_executed的功能与binlog的功能有一些类似, gtid_executed只有 gtid_mode 或者 ON_PERMISSIVE 开启的时候才会生效.
gtid_executed 表存储GDIT的方式有两种:

  1. log_bin开关打开, 在InnoDB 存储引擎中, 只有当一个事务执行完成, Commit之后, 才会将它的GTID写入这张表, 这与写入binlog的时机相同.
  2. 在其他的存储引擎中, 只有当binlog 调整或者服务器关机的时候, 才会将binlog中的所有的事务的 GDIT 写入gtid_executed 表中.
posted @ 2024-08-08 14:24  虾野百鹤  阅读(16)  评论(0编辑  收藏  举报