MK
摩柯社区 - 一个极简的技术知识社区
AI 面试

MariaDB GTID复制技术详解与实践

2022-09-137.1k 阅读

MariaDB GTID 复制技术基础

GTID 概念

全局事务标识符(Global Transaction Identifier,GTID)是 MariaDB 中用于唯一标识数据库事务的一种机制。在传统的基于日志位置的复制中,主库通过二进制日志记录数据库的修改操作,从库根据日志位置来重放这些操作。然而,这种方式在处理复杂拓扑结构和故障恢复时存在诸多不便。

GTID 的引入解决了这些问题。每个在主库上提交的事务都会被分配一个唯一的 GTID。GTID 由两部分组成:源标识符(source identifier)和事务编号(transaction number)。源标识符通常是主库的服务器 UUID,事务编号则是该服务器上自启动以来的事务序列号。例如,一个 GTID 可能看起来像 123e4567-e89b-12d3-a456-426614174000:10,其中 123e4567-e89b-12d3-a456-426614174000 是服务器 UUID,10 是事务编号。

GTID 工作原理

  1. 事务提交:当一个事务在主库上提交时,主库会为该事务生成一个 GTID,并将其记录在二进制日志中。同时,该 GTID 也会被记录到主库的 gtid_executed 集合中,这个集合记录了主库上已经执行过的所有 GTID。
  2. 日志传输:主库将包含 GTID 的二进制日志事件发送给从库。从库接收到这些日志事件后,首先检查事件中的 GTID 是否已经在自己的 gtid_executed 集合中。如果已经存在,说明该事务已经执行过,从库会跳过这个事件;如果不存在,从库会执行这个事务,并将对应的 GTID 添加到自己的 gtid_executed 集合中。
  3. 故障恢复:在故障恢复场景下,从库可以通过 gtid_executed 集合快速确定需要从主库重新获取哪些日志事件,而不需要依赖传统的日志位置信息。这使得故障恢复过程更加简单和可靠。

MariaDB GTID 复制配置

主库配置

  1. 编辑配置文件:打开 MariaDB 的配置文件(通常是 /etc/mysql/mariadb.conf.d/50-server.cnf),添加或修改以下配置项:
[mysqld]
log-bin=mysql-bin
server-id=1
gtid-mode=ON
enforce-gtid-consistency=ON
  • log-bin=mysql-bin:开启二进制日志,这是复制的基础。
  • server-id=1:为服务器设置一个唯一的 ID,不同服务器的 ID 不能相同。
  • gtid-mode=ON:启用 GTID 模式。
  • enforce-gtid-consistency=ON:强制 GTID 一致性,确保所有可能影响 GTID 一致性的操作都被禁止,例如某些不支持 GTID 的存储引擎操作。
  1. 重启 MariaDB 服务:修改配置文件后,重启 MariaDB 服务使配置生效:
sudo systemctl restart mariadb
  1. 创建复制用户:登录到 MariaDB 主库,创建一个用于从库连接的复制用户:
CREATE USER 'repl_user'@'%' IDENTIFIED BY 'password';
GRANT REPLICATION SLAVE ON *.* TO 'repl_user'@'%';
FLUSH PRIVILEGES;

这里创建了一个名为 repl_user 的用户,允许来自任何主机(%)的连接,并授予其复制从库权限。

从库配置

  1. 编辑配置文件:同样在从库的 MariaDB 配置文件中添加或修改以下配置项:
[mysqld]
server-id=2
gtid-mode=ON
enforce-gtid-consistency=ON

server-id 设置为与主库不同的值,这里设为 2。其他配置与主库类似。

  1. 重启 MariaDB 服务:修改配置后重启服务:
sudo systemctl restart mariadb
  1. 配置从库连接主库:登录到 MariaDB 从库,执行以下命令配置与主库的连接:
CHANGE MASTER TO
    MASTER_HOST='master_host_ip',
    MASTER_USER='repl_user',
    MASTER_PASSWORD='password',
    MASTER_AUTO_POSITION=1;
  • MASTER_HOST:主库的 IP 地址。
  • MASTER_USERMASTER_PASSWORD:前面在主库创建的复制用户及其密码。
  • MASTER_AUTO_POSITION=1:启用基于 GTID 的自动定位,从库会根据 GTID 自动确定从主库的哪个位置开始复制。
  1. 启动从库复制:配置完成后,启动从库的复制进程:
START SLAVE;
  1. 检查复制状态:使用以下命令检查从库的复制状态:
SHOW SLAVE STATUS \G;

重点关注 Slave_IO_RunningSlave_SQL_Running 是否都为 Yes,以及 Seconds_Behind_Master 是否为 0 或接近 0。如果 Slave_IO_RunningNo,可能是网络连接或主库配置问题;如果 Slave_SQL_RunningNo,可能是从库执行事务时遇到错误。

MariaDB GTID 复制高级特性

GTID 与多主复制

在传统的复制拓扑中,多主复制的配置和管理比较复杂,容易出现数据冲突。而 GTID 为多主复制提供了更好的解决方案。

在多主复制环境中,每个主库都有自己唯一的 UUID。当事务在不同主库之间传播时,GTID 可以确保每个事务在整个集群中具有唯一性。例如,假设我们有两个主库 A 和 B,客户端在主库 A 上提交了一个事务,主库 A 为该事务生成 GTID A_uuid:1。当这个事务通过复制传播到主库 B 时,主库 B 会检查自己的 gtid_executed 集合,发现该 GTID 不存在,于是执行该事务,并将 A_uuid:1 添加到自己的 gtid_executed 集合中。

为了实现多主复制,每个主库都需要配置为可以接收来自其他主库的复制连接。例如,在第二个主库的配置文件中,除了常规的 GTID 配置外,还需要设置:

log-bin=mysql-bin
server-id=3

并创建用于其他主库连接的复制用户:

CREATE USER 'repl_user_from_other_master'@'%' IDENTIFIED BY 'password';
GRANT REPLICATION SLAVE ON *.* TO 'repl_user_from_other_master'@'%';
FLUSH PRIVILEGES;

然后在每个主库上,都需要使用 CHANGE MASTER TO 命令配置与其他主库的连接,例如:

CHANGE MASTER TO
    MASTER_HOST='other_master_host_ip',
    MASTER_USER='repl_user_from_other_master',
    MASTER_PASSWORD='password',
    MASTER_AUTO_POSITION=1;

GTID 与并行复制

MariaDB 的 GTID 复制支持并行复制,这可以显著提高从库的复制性能。在传统的基于日志位置的复制中,从库通常是单线程地重放主库的二进制日志,这在高并发场景下可能成为性能瓶颈。

GTID 并行复制基于 GTID 的特性,允许从库将不同的事务分配到多个线程中并行执行。从库会根据 GTID 的顺序和依赖关系,将无依赖的事务分配到不同的线程中执行。

要启用 GTID 并行复制,在从库的配置文件中添加以下配置项:

slave_parallel_type=LOGICAL_CLOCK
slave_parallel_workers=4
  • slave_parallel_type=LOGICAL_CLOCK:设置并行复制类型为基于逻辑时钟,这是 GTID 并行复制常用的类型。
  • slave_parallel_workers=4:设置并行工作线程数为 4,可以根据服务器的硬件资源和负载情况进行调整。

启用并行复制后,从库在重放主库日志时,会将不同的事务分配到多个线程中并行执行,从而加快复制速度。但需要注意的是,某些事务之间可能存在依赖关系,例如一个事务更新了表 A,另一个事务依赖于表 A 的更新结果再更新表 B,这种情况下这两个事务不能并行执行,从库会根据 GTID 的逻辑时钟来确保事务执行的顺序正确性。

MariaDB GTID 复制实践案例

简单主从复制实践

  1. 环境准备:我们有两台服务器,一台作为主库(IP:192.168.1.100),另一台作为从库(IP:192.168.1.101),均安装了 MariaDB 10.5 版本。
  2. 主库配置
  • 按照前面主库配置部分的步骤,修改主库的配置文件 /etc/mysql/mariadb.conf.d/50-server.cnf
[mysqld]
log-bin=mysql-bin
server-id=1
gtid-mode=ON
enforce-gtid-consistency=ON
  • 重启 MariaDB 服务:
sudo systemctl restart mariadb
  • 创建复制用户:
CREATE USER 'repl_user'@'%' IDENTIFIED BY 'password';
GRANT REPLICATION SLAVE ON *.* TO 'repl_user'@'%';
FLUSH PRIVILEGES;
  1. 从库配置
  • 修改从库的配置文件 /etc/mysql/mariadb.conf.d/50-server.cnf
[mysqld]
server-id=2
gtid-mode=ON
enforce-gtid-consistency=ON
  • 重启 MariaDB 服务:
sudo systemctl restart mariadb
  • 配置从库连接主库:
CHANGE MASTER TO
    MASTER_HOST='192.168.1.100',
    MASTER_USER='repl_user',
    MASTER_PASSWORD='password',
    MASTER_AUTO_POSITION=1;
  • 启动从库复制:
START SLAVE;
  • 检查从库复制状态:
SHOW SLAVE STATUS \G;

确保 Slave_IO_RunningSlave_SQL_Running 都为 YesSeconds_Behind_Master 为 0 或接近 0。 4. 测试复制:在主库上创建一个测试数据库和表,并插入数据:

CREATE DATABASE test;
USE test;
CREATE TABLE users (id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(50));
INSERT INTO users (name) VALUES ('Alice'), ('Bob');

然后在从库上检查是否成功复制:

USE test;
SELECT * FROM users;

应该能看到与主库相同的数据。

多主复制实践

  1. 环境准备:现在有三台服务器,第一台主库(IP:192.168.1.100,server-id = 1),第二台主库(IP:192.168.1.101,server-id = 3),以及一台从库(IP:192.168.1.102,server-id = 2)。
  2. 主库 1 配置
  • 配置文件 /etc/mysql/mariadb.conf.d/50-server.cnf
[mysqld]
log-bin=mysql-bin
server-id=1
gtid-mode=ON
enforce-gtid-consistency=ON
  • 重启服务:
sudo systemctl restart mariadb
  • 创建复制用户:
CREATE USER 'repl_user'@'%' IDENTIFIED BY 'password';
GRANT REPLICATION SLAVE ON *.* TO 'repl_user'@'%';
FLUSH PRIVILEGES;
  1. 主库 2 配置
  • 配置文件 /etc/mysql/mariadb.conf.d/50-server.cnf
[mysqld]
log-bin=mysql-bin
server-id=3
gtid-mode=ON
enforce-gtid-consistency=ON
  • 重启服务:
sudo systemctl restart mariadb
  • 创建复制用户:
CREATE USER 'repl_user'@'%' IDENTIFIED BY 'password';
GRANT REPLICATION SLAVE ON *.* TO 'repl_user'@'%';
FLUSH PRIVILEGES;
  1. 主库间相互配置
  • 在主库 1 上配置连接主库 2:
CHANGE MASTER TO
    MASTER_HOST='192.168.1.101',
    MASTER_USER='repl_user',
    MASTER_PASSWORD='password',
    MASTER_AUTO_POSITION=1;
START SLAVE;
  • 在主库 2 上配置连接主库 1:
CHANGE MASTER TO
    MASTER_HOST='192.168.1.100',
    MASTER_USER='repl_user',
    MASTER_PASSWORD='password',
    MASTER_AUTO_POSITION=1;
START SLAVE;
  1. 从库配置
  • 配置文件 /etc/mysql/mariadb.conf.d/50-server.cnf
[mysqld]
server-id=2
gtid-mode=ON
enforce-gtid-consistency=ON
  • 重启服务:
sudo systemctl restart mariadb
  • 配置连接主库 1:
CHANGE MASTER TO
    MASTER_HOST='192.168.1.100',
    MASTER_USER='repl_user',
    MASTER_PASSWORD='password',
    MASTER_AUTO_POSITION=1;
START SLAVE;
  • 配置连接主库 2(可选,实现双活主从):
CHANGE MASTER TO
    MASTER_HOST='192.168.1.101',
    MASTER_USER='repl_user',
    MASTER_PASSWORD='password',
    MASTER_AUTO_POSITION=1;
START SLAVE;
  1. 测试多主复制:在主库 1 上创建一个新数据库和表并插入数据:
CREATE DATABASE test_multi;
USE test_multi;
CREATE TABLE products (id INT PRIMARY KEY AUTO_INCREMENT, product_name VARCHAR(50));
INSERT INTO products (product_name) VALUES ('Product 1');

在主库 2 上检查是否能看到相同的数据:

USE test_multi;
SELECT * FROM products;

同样,在主库 2 上进行数据操作,也应该能在主库 1 和从库上看到同步的数据。

MariaDB GTID 复制故障排查

从库复制停止

  1. 检查网络连接:首先确保从库与主库之间的网络连接正常。可以使用 ping 命令检查网络连通性,例如:
ping 192.168.1.100

如果网络不通,检查防火墙设置,确保 MariaDB 服务端口(默认为 3306)没有被阻塞。在 Linux 系统上,可以使用 iptables 命令查看和修改防火墙规则,例如:

sudo iptables -L
sudo iptables -A INPUT -p tcp --dport 3306 -j ACCEPT
  1. 检查主库状态:登录到主库,检查二进制日志是否正常工作。可以使用以下命令查看二进制日志状态:
SHOW MASTER STATUS;

确保 Log_namePosition 字段有正常的值。如果二进制日志没有正常记录,检查主库的配置文件中 log-bin 相关配置是否正确,以及磁盘空间是否充足,因为二进制日志文件会占用磁盘空间。 3. 检查从库状态:在从库上使用 SHOW SLAVE STATUS \G 命令详细查看从库状态。

  • 如果 Slave_IO_RunningNo,可能是连接主库失败。检查 SHOW SLAVE STATUS \G 中的 Last_IO_Error 字段,常见的错误可能是用户名密码错误、主库 IP 地址错误等。根据错误提示进行相应修改,例如,如果是用户名密码错误,可以重新使用 CHANGE MASTER TO 命令修改连接配置:
CHANGE MASTER TO
    MASTER_PASSWORD='new_password';
START SLAVE;
  • 如果 Slave_SQL_RunningNo,检查 Last_SQL_Error 字段。可能是从库在执行事务时遇到错误,例如主库和从库之间的数据结构不一致,或者某个事务在从库上执行失败。例如,如果从库上缺少主库中某个表,需要在从库上创建相同结构的表。如果是数据类型不一致导致的错误,需要根据实际情况调整数据类型。

GTID 一致性问题

  1. 检查 GTID 模式配置:确保主库和从库都正确配置了 GTID 模式。在主库和从库的配置文件中,检查 gtid-mode=ONenforce-gtid-consistency=ON 是否正确设置,并且重启 MariaDB 服务使配置生效。
  2. 检查 GTID 执行集合:在主库和从库上分别使用以下命令查看 gtid_executed 集合:
SELECT @@GLOBAL.gtid_executed;

对比主库和从库的 gtid_executed 集合,确保从库的集合是主库集合的子集。如果从库的 gtid_executed 集合缺少某些 GTID,可能是复制过程中出现了问题。可以尝试在从库上使用 RESET SLAVE ALL 命令重置从库状态,然后重新配置从库连接主库:

STOP SLAVE;
RESET SLAVE ALL;
CHANGE MASTER TO
    MASTER_HOST='master_host_ip',
    MASTER_USER='repl_user',
    MASTER_PASSWORD='password',
    MASTER_AUTO_POSITION=1;
START SLAVE;

但需要注意,RESET SLAVE ALL 会清除从库的所有复制相关信息,使用前要确保了解其影响。

  1. 避免不支持 GTID 的操作:由于 enforce-gtid-consistency=ON 会禁止某些不支持 GTID 的操作,例如在使用不支持 GTID 的存储引擎(如 MyISAM)进行数据操作时可能会导致 GTID 一致性问题。尽量使用支持 GTID 的存储引擎,如 InnoDB。如果必须使用 MyISAM,确保在主库和从库上的操作一致,并且在操作前停止复制,操作完成后再重新启动复制。

通过以上对 MariaDB GTID 复制技术的详细介绍、配置方法、高级特性、实践案例以及故障排查,希望读者能够深入理解并熟练应用 GTID 复制技术,构建高效、可靠的 MariaDB 数据库复制架构。在实际应用中,还需要根据具体的业务需求和系统环境进行适当的调整和优化。