MySQL 实例启动后,
gtid_executed 的初始化是一个结合了持久化存储和二进制日志扫描的过程,其核心目标是准确重建服务器已知的所有已提交事务的 GTID 集合。
gtid_executed 的初始化
- 从 mysql.gtid_executed 表加载(主要来源)
- 持久化存储:在实例正常运行期间,MySQL 会定期(例如在 binlog 文件轮换时或服务器关闭时)将内存中的 gtid_executed 集合进行"压缩"并持久化到 mysql.gtid_executed 系统表中。
- 初始化基础值:实例启动时,首先会从 mysql.gtid_executed 表中读取所有记录,将这些记录的 GTID 集合合并,作为初始化 @@GLOBAL.gtid_executed 系统变量的基础值。这是最快、最主要的数据来源。
- 扫描 Binlog 文件以进行验证和补充
- 扫描现存文件:继上一步之后,服务器会扫描磁盘上所有现存的(未被 PURGE 的)binlog 文件。
- 重建 Binlog 中的 GTID 集合:对于每个 binlog 文件,服务器通过解析其头部的 Previous_gtids_log_event 和文件体内的 Gtid_log_event,计算出该文件所包含的完整 GTID 区间。
- 计算并合并:服务器将所有现存 binlog 文件中的 GTID 集合合并,得到一个代表"磁盘上记录的已执行事务"的 GTID 集合,我们称之为 binlog_gtid_set。
- 计算最终的 gtid_executed
最终的
@@GLOBAL.gtid_executed 值是以下两个集合的并集(UNION): gtid_executed = 从mysql.gtid_executed表加载的集合 ∪ binlog_gtid_set
这样设计的目的:
- 效率:从表加载速度远快于解析所有 binlog 文件。
- 安全性/正确性:mysql.gtid_executed 表可能由于某些原因(如未及时刷新)未能包含最新提交的事务。扫描 binlog 确保了任何已经记录到二进制日志中的事务都不会被遗漏,从而保证了 gtid_executed 集合的绝对正确性。
衍生出 gtid_purged
在
gtid_executed 确定之后,@@GLOBAL.gtid_purged 的值便通过一个简单的集合差运算得出: gtid_purged = gtid_executed - binlog_gtid_set 这个结果代表的是已经从磁盘上被清除的 binlog 文件中所记录的那些事务。
上面过程的流程如下图:
MySQL实例启动 从mysql.gtid_executed表加载GTID集合 扫描所有现存binlog文件, 计算binlog_gtid_set 计算最终gtid_executed: 表中的gtid集合 U binlog中的gtid集合 计算gtid_purged = gtid_executed - binlog_gtid_set