好的,我们开始今天的讲座,主题是:GTID
(全局事务ID)的实现,以及GTID
如何保证主从复制的唯一性和一致性。
一、传统复制的痛点
在深入GTID
之前,我们需要了解传统MySQL复制存在的一些问题,正是这些问题促使了GTID
的诞生。
- 依赖二进制日志文件名和位置: 传统的复制配置需要指定主库的二进制日志文件名和位置(
binlog_file
和binlog_pos
)作为从库的起始复制点。如果主库发生切换(例如,故障转移),或者进行了reset master
操作,这些信息可能会失效,导致复制中断或数据不一致。 - 复杂拓扑管理: 在复杂的复制拓扑中(例如,多级复制),管理二进制日志文件名和位置变得非常困难且容易出错。
- 事务丢失的风险: 如果从库在复制过程中意外崩溃,并且没有完全处理完某个事务,重启后可能无法自动定位到正确的位置继续复制,导致事务丢失。
- 主从切换困难: 主库发生故障时,需要手动更新所有从库的复制配置,指向新的主库,这个过程容易出错,且耗时较长。
二、GTID:全局事务ID的定义与原理
GTID
(Global Transaction ID) 是MySQL 5.6版本引入的一种全局唯一的事务标识符。它解决了传统复制中依赖二进制日志文件名和位置的痛点,简化了复制配置和管理,提高了复制的可靠性和一致性。
2.1 GTID的结构
一个GTID
由两部分组成:
source_id
(Server UUID): 生成该事务的服务器的唯一UUID。这个UUID在MySQL服务器启动时生成,并存储在server_uuid
系统变量中。transaction_id
(Sequence Number): 在该服务器上生成的事务的序列号,从1开始递增。
因此,一个GTID
的形式如下:
source_id:transaction_id
例如:
3E11FA47-71CA-11E1-9E33-C80AA9429562:23
2.2 GTID的工作原理
-
生成GTID: 当一个事务在主库上提交时,MySQL会自动为该事务生成一个唯一的
GTID
。 -
记录GTID: 这个
GTID
会被记录到二进制日志中,并且也会更新到gtid_executed
集合中,表示该事务已经执行。 -
复制GTID: 从库在复制过程中,会从主库接收二进制日志,并从中提取
GTID
。 -
GTID追踪: 从库会维护一个
gtid_executed
集合,记录已经执行过的GTID
。在应用二进制日志之前,从库会检查该GTID
是否已经存在于gtid_executed
集合中。 -
跳过已执行事务: 如果
GTID
已经存在,则表示该事务已经被执行过,从库会跳过该事务,避免重复执行。 -
执行新事务: 如果
GTID
不存在,则表示这是一个新的事务,从库会执行该事务,并将该GTID
添加到gtid_executed
集合中。
2.3 GTID相关的系统变量
以下是一些与GTID
相关的重要的MySQL系统变量:
变量名 | 描述 |
---|---|
gtid_mode |
控制GTID模式的启用和强制执行。取值可以为:OFF 、ON 、OFF_PERMISSIVE 、ON_PERMISSIVE 、OFF_STRICT 、ON_STRICT 。ON 表示启用GTID,ENFORCE_GTID_CONSISTENCY 必须为ON 。STRICT 模式会禁止创建临时表以及不允许执行不写入binlog的语句。 |
enforce_gtid_consistency |
控制是否强制执行GTID的一致性。如果设置为ON ,则不允许执行可能导致数据不一致的操作,例如创建临时表。建议设置为ON ,保证数据一致性。 |
gtid_executed |
记录已经执行过的GTID 集合。在主库上,记录所有已经提交的事务的GTID 。在从库上,记录所有已经应用的事务的GTID 。 |
gtid_purged |
记录可以被安全purge的GTID 集合。表示早于这个集合的GTID的binlog已经被purge,从库不再需要这些binlog。 |
server_uuid |
记录服务器的唯一UUID。每个MySQL服务器都应该有一个唯一的UUID。 |
binlog_gtid_simple_recovery |
控制在崩溃恢复期间如何查找可用的二进制日志。设置为ON 可以提高恢复速度,但可能会导致一些旧的二进制日志被删除。 |
三、GTID的配置与使用
3.1 启用GTID
要启用GTID
,需要在MySQL配置文件(例如,my.cnf
)中添加以下配置:
[mysqld]
gtid_mode = ON
enforce_gtid_consistency = ON
log_bin = mysql-bin # 启用二进制日志
server_id = 1 # 设置服务器ID (每个服务器ID需要唯一)
binlog_format = ROW # 推荐使用ROW格式
gtid_mode = ON
:启用GTID
模式。enforce_gtid_consistency = ON
:强制执行GTID
一致性。log_bin = mysql-bin
:启用二进制日志。GTID
依赖于二进制日志。server_id = 1
:设置服务器ID。binlog_format = ROW
:推荐使用ROW
格式。ROW
格式记录了每一行数据的变化,更适合GTID
的复制。
修改配置文件后,需要重启MySQL服务器。
3.2 初始化GTID
如果服务器已经存在数据,并且之前没有启用GTID
,则需要执行以下步骤来初始化GTID
:
-
备份数据: 在进行任何操作之前,务必备份数据,以防万一。
-
停止所有从库的复制:
STOP SLAVE;
-
在所有服务器上设置
gtid_mode
为ON_PERMISSIVE
:SET GLOBAL gtid_mode = ON_PERMISSIVE; SET GLOBAL enforce_gtid_consistency = ON;
-
重启所有服务器。
-
在主库上执行:
SET GLOBAL gtid_mode = ON;
-
重启主库。
-
在从库上执行:
SET GLOBAL gtid_mode = ON;
-
重启从库。
-
启动所有从库的复制:
START SLAVE;
3.3 配置从库复制
启用GTID
后,配置从库复制变得非常简单。只需要指定主库的地址和凭据,MySQL会自动找到正确的复制起始点。
CHANGE MASTER TO
MASTER_HOST='master_host',
MASTER_USER='replication_user',
MASTER_PASSWORD='replication_password',
MASTER_AUTO_POSITION = 1;
START SLAVE;
MASTER_AUTO_POSITION = 1
:告诉从库使用GTID
自动定位复制起始点。
四、GTID的优势
- 简化复制配置: 无需手动指定二进制日志文件名和位置,简化了复制配置和管理。
- 自动故障转移: 当主库发生故障时,可以将任何一个从库提升为新的主库,而无需修改其他从库的复制配置。所有从库会自动连接到新的主库,并从正确的位置继续复制。
- 提高复制可靠性: 通过
GTID
追踪,可以避免事务丢失和重复执行,提高了复制的可靠性和一致性。 - 支持多源复制:
GTID
使得多源复制成为可能,一个从库可以同时从多个主库复制数据。 - 简化拓扑管理: 在复杂的复制拓扑中,
GTID
可以简化拓扑管理,提高可维护性。
五、GTID的局限性
- 需要MySQL 5.6或更高版本:
GTID
是在MySQL 5.6版本中引入的,因此需要使用该版本或更高版本的MySQL。 - 需要启用二进制日志:
GTID
依赖于二进制日志,因此需要启用二进制日志。 - 不支持所有存储引擎:
GTID
只支持事务性存储引擎,例如InnoDB。 - 初期迁移成本: 如果服务器已经存在数据,并且之前没有启用
GTID
,则需要进行初始化操作,这可能会有一定的迁移成本。 ENFORCE_GTID_CONSISTENCY
限制: 启用ENFORCE_GTID_CONSISTENCY
会禁止创建临时表,以及不允许执行不写入binlog的语句,对某些应用场景有一定限制。
六、代码示例
6.1 查看GTID状态
SHOW GLOBAL VARIABLES LIKE 'gtid_mode';
SHOW GLOBAL VARIABLES LIKE 'enforce_gtid_consistency';
SHOW GLOBAL VARIABLES LIKE 'server_uuid';
6.2 查看已执行的GTID
SELECT @@gtid_executed; -- 这种方式在MySQL 8.0之后不推荐使用
SHOW GLOBAL STATUS LIKE 'Com_show_gtid_log'; -- MySQL 8.0 推荐使用
6.3 设置GTID模式 (谨慎操作)
-- 示例:设置GTID模式为ON (需要先设置为ON_PERMISSIVE)
SET GLOBAL gtid_mode = ON_PERMISSIVE;
-- 重启MySQL
SET GLOBAL gtid_mode = ON;
-- 重启MySQL
6.4 模拟主从切换 (假设master_1 宕机,提升slave_1 为新的master)
-
在slave_1上执行 (提升为新的主库):
STOP SLAVE; RESET MASTER; -- 重要:将slave_1的binlog重置,并生成新的server_uuid
-
在其他从库 (slave_2, slave_3 等) 上执行:
STOP SLAVE; CHANGE MASTER TO MASTER_HOST='slave_1_host', -- 新的主库地址 MASTER_USER='replication_user', MASTER_PASSWORD='replication_password', MASTER_AUTO_POSITION = 1; START SLAVE;
七、GTID与数据一致性
GTID
通过以下机制来保证数据的一致性:
- 全局唯一性: 每个事务都有一个全局唯一的
GTID
,确保不会出现重复的事务。 - 事务追踪: 从库会追踪已经执行过的
GTID
,避免重复执行事务。 - 跳过已执行事务: 如果从库发现某个
GTID
已经存在于gtid_executed
集合中,则会跳过该事务,避免重复执行。 ENFORCE_GTID_CONSISTENCY
: 强制执行GTID
一致性,禁止执行可能导致数据不一致的操作。
八、GTID的性能影响
启用GTID
会对性能产生一定的影响,主要体现在以下几个方面:
- 生成GTID: 生成
GTID
需要一定的计算开销,但通常可以忽略不计。 - 记录GTID: 将
GTID
记录到二进制日志中会增加磁盘I/O,但可以使用固态硬盘(SSD)来缓解这个问题。 - GTID追踪: 从库需要维护一个
gtid_executed
集合,这会消耗一定的内存。 - GTID查找: 从库在应用二进制日志之前,需要检查该
GTID
是否已经存在于gtid_executed
集合中,这会增加CPU开销。
总的来说,GTID
对性能的影响是可控的,可以通过优化硬件和配置来降低性能影响。例如,使用SSD、增加内存、调整gtid_executed_compression_level
等。
九、GTID相关的常见问题
-
GTID_NEXT
:GTID_NEXT
是一个会话级别的变量,用于指定下一个事务的GTID
。通常情况下,不需要手动设置GTID_NEXT
,MySQL会自动管理。只有在特殊情况下,例如从其他数据库迁移数据时,才需要手动设置GTID_NEXT
。 -
gtid_executed
集合的大小:gtid_executed
集合会随着时间的推移而增长,可能会占用大量的内存。可以通过定期清理gtid_executed
集合来释放内存。可以使用PURGE BINARY LOGS
语句来清理二进制日志,并更新gtid_purged
变量。 -
lost update
问题:GTID
可以避免重复执行事务,但不能解决lost update
问题。lost update
问题是指多个客户端同时修改同一行数据,导致其中一些修改丢失。要解决lost update
问题,需要使用锁机制,例如悲观锁或乐观锁。 -
升级到GTID的注意事项: 从非GTID环境升级到GTID环境需要谨慎操作,务必备份数据,并按照正确的步骤进行操作,以避免数据丢失或不一致。
十、GTID与其他复制技术
-
增强半同步复制: GTID可以与增强半同步复制结合使用,进一步提高复制的可靠性。增强半同步复制可以确保事务在主库提交之前,必须至少同步到一台从库。
-
MGR (MySQL Group Replication): MGR是MySQL 5.7版本引入的一种基于组复制的技术。MGR内部使用了GTID来追踪事务,保证数据一致性。
总结:GTID简化复制,提高可靠性
GTID通过全局唯一标识事务,简化了MySQL复制的配置和管理,提高了复制的可靠性和一致性。它解决了传统复制中依赖日志文件名和位置的痛点,并支持自动故障转移和多源复制等高级特性。
配置和使用GTID:开启GTID模式,自动定位复制
启用GTID需要修改MySQL配置文件并重启服务。配置从库复制时,只需指定主库地址和凭据,并设置MASTER_AUTO_POSITION = 1
,即可自动定位复制起始点。
GTID的优势与限制:简化管理,但需高版本MySQL
GTID简化复制配置、提高可靠性,但也需要MySQL 5.6或更高版本,并依赖二进制日志。需要权衡其优势与限制,选择适合的复制方案。