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

MySQL复制技术概览与问题解决

2021-04-242.5k 阅读

MySQL 复制技术基础

复制原理概述

MySQL 复制是一种数据同步机制,它允许将一台 MySQL 服务器(主服务器,Master)的数据更改复制到一台或多台其他 MySQL 服务器(从服务器,Slave)。这种机制基于主从模型,主服务器记录所有的数据更改操作到二进制日志(Binary Log)中,从服务器通过读取主服务器的二进制日志并在本地重放这些操作,从而保持与主服务器的数据一致性。

具体来说,复制过程分为三个主要步骤:

  1. 日志记录:主服务器在执行任何修改数据的语句(如 INSERT、UPDATE、DELETE)时,会将这些操作记录到二进制日志文件中。每个二进制日志文件都有一个唯一的编号,并且记录了操作发生的顺序。
  2. 日志传输:从服务器通过一个 I/O 线程连接到主服务器,请求获取主服务器二进制日志中尚未同步的部分。主服务器通过一个二进制日志转储线程(Binlog Dump Thread)将相应的二进制日志内容发送给从服务器。从服务器将接收到的日志内容存储在本地的中继日志(Relay Log)中。
  3. 日志重放:从服务器的 SQL 线程读取中继日志中的内容,并在本地数据库中按照日志记录的顺序执行相应的操作,从而实现数据的同步。

复制拓扑结构

  1. 一主一从:这是最基本的复制拓扑结构,一台主服务器将数据复制到一台从服务器。这种结构简单,适用于对数据冗余和读扩展需求较低的场景。例如,在一个小型的 Web 应用中,主服务器处理所有的写操作,从服务器用于备份或者分担一些读操作。
  2. 一主多从:一台主服务器将数据同时复制到多台从服务器。这种结构常用于读操作负载较高的场景,多台从服务器可以分担读请求,提高系统的整体读性能。比如,在一个大型的电商网站中,大量的用户浏览商品信息产生大量读请求,通过一主多从结构,多台从服务器可以同时处理这些读请求。
  3. 主主复制:两台服务器互为对方的主服务器和从服务器,它们之间互相复制数据。这种结构可以提高系统的可用性,任何一台服务器都可以处理写操作。但是由于两台服务器都可以写,需要注意避免数据冲突。例如,在一个对高可用性要求较高的数据库环境中,主主复制可以保证在一台服务器出现故障时,另一台服务器可以无缝接管所有操作。
  4. 主从链:主服务器将数据复制到一台从服务器,这台从服务器又作为另一台从服务器的主服务器,依此类推形成一条链。这种结构可以在一定程度上减轻主服务器的负载,适合在网络带宽有限或者需要逐步扩展的场景中使用。

配置主服务器

  1. 启用二进制日志:编辑 MySQL 配置文件(通常是 my.cnf 或 my.ini),在 [mysqld] 部分添加或修改以下配置:
log-bin=mysql-bin
server-id=1

log-bin 参数启用二进制日志功能,并指定二进制日志文件的前缀为 mysql-binserver-id 是服务器的唯一标识符,在整个复制环境中必须是唯一的,这里设置为 1。 2. 重启 MySQL 服务:修改配置文件后,重启 MySQL 服务使配置生效。在 Linux 系统下,可以使用以下命令:

sudo systemctl restart mysql

在 Windows 系统下,可以通过服务管理工具找到 MySQL 服务并重启。 3. 创建用于复制的用户:登录到 MySQL 主服务器,创建一个专门用于从服务器连接复制的用户,并授予 REPLICATION SLAVE 权限。例如:

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

这里创建了一个名为 replication_user 的用户,允许来自任何主机(%)的连接,密码为 password。并授予该用户复制相关的权限,最后刷新权限使设置生效。 4. 获取主服务器状态:执行以下命令获取主服务器的二进制日志文件名和当前位置:

SHOW MASTER STATUS;

输出结果类似如下:

+------------------+----------+--------------+------------------+-------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000003 | 154      |              |                  |                   |
+------------------+----------+--------------+------------------+-------------------+

记录下 FilePosition 的值,后续配置从服务器时会用到。

配置从服务器

  1. 设置服务器 ID:编辑从服务器的 MySQL 配置文件,在 [mysqld] 部分添加或修改 server-id 参数,确保其在整个复制环境中是唯一的,例如:
server-id=2
  1. 重启 MySQL 服务:修改配置后,重启从服务器的 MySQL 服务。
  2. 配置主服务器连接信息:登录到从服务器的 MySQL 客户端,执行以下命令配置主服务器的连接信息:
CHANGE MASTER TO
    MASTER_HOST='master_server_ip',
    MASTER_USER='replication_user',
    MASTER_PASSWORD='password',
    MASTER_LOG_FILE='mysql-bin.000003',
    MASTER_LOG_POS=154;

其中 master_server_ip 是主服务器的 IP 地址,MASTER_LOG_FILEMASTER_LOG_POS 是前面在主服务器上通过 SHOW MASTER STATUS 获取的值。 4. 启动从服务器:执行以下命令启动从服务器的复制功能:

START SLAVE;
  1. 检查从服务器状态:执行以下命令检查从服务器的复制状态:
SHOW SLAVE STATUS \G;

重点关注以下两个参数:

  • Slave_IO_RunningSlave_SQL_Running 都应该为 Yes,表示 I/O 线程和 SQL 线程都在正常运行。
  • Seconds_Behind_Master 表示从服务器落后主服务器的时间(以秒为单位),理想情况下这个值应该接近于 0。如果这个值较大,说明从服务器同步延迟较大,需要排查原因。

MySQL 复制技术深入

基于 GTID 的复制

  1. GTID 简介:全局事务标识符(Global Transaction Identifier,GTID)是 MySQL 5.6 引入的一种新的复制机制。在传统的基于日志位置的复制中,从服务器通过记录主服务器的二进制日志文件名和位置来同步数据,这种方式在主服务器进行二进制日志切换或者故障恢复时可能会出现一些复杂的配置问题。而 GTID 为每个在主服务器上提交的事务分配一个全局唯一的标识符,从服务器通过 GTID 来跟踪和同步事务,使得复制过程更加简单和可靠。
  2. GTID 工作原理:当一个事务在主服务器上提交时,主服务器会为该事务生成一个 GTID,格式为 domain_id:server_id:transaction_id。其中 domain_id 是一个全局唯一的标识符,server_id 是主服务器的 ID,transaction_id 是该服务器上的事务序列号。主服务器将包含 GTID 的事务记录到二进制日志中,从服务器在同步时,根据 GTID 来判断哪些事务需要执行,而不需要依赖日志文件名和位置。
  3. 配置基于 GTID 的复制
    • 主服务器配置:在主服务器的配置文件中添加以下配置:
gtid_mode=ON
enforce_gtid_consistency=ON
log-bin=mysql-bin
server-id=1

gtid_mode=ON 启用 GTID 模式,enforce_gtid_consistency=ON 确保所有事务在 GTID 模式下以一致的方式执行。 - 从服务器配置:在从服务器的配置文件中添加:

gtid_mode=ON
enforce_gtid_consistency=ON
server-id=2
- **配置主从连接**:在从服务器上,配置主服务器连接信息时,不再需要指定 `MASTER_LOG_FILE` 和 `MASTER_LOG_POS`,而是使用 GTID 相关的配置:
CHANGE MASTER TO
    MASTER_HOST='master_server_ip',
    MASTER_USER='replication_user',
    MASTER_PASSWORD='password',
    MASTER_AUTO_POSITION=1;

MASTER_AUTO_POSITION=1 表示使用 GTID 自动定位机制。然后启动从服务器复制功能并检查状态,方法与传统复制类似。

半同步复制

  1. 半同步复制原理:在传统的异步复制中,主服务器在将事务写入二进制日志并发送给从服务器后,就立即向客户端返回成功响应,而不管从服务器是否已经接收到并应用了该事务。这可能导致在主服务器故障时,部分已提交的事务还未同步到从服务器,从而造成数据丢失。半同步复制介于异步复制和同步复制之间,主服务器在将事务写入二进制日志后,会等待至少一个从服务器确认已经接收到该事务,才向客户端返回成功响应。这样可以在一定程度上保证数据的一致性和可靠性。
  2. 配置半同步复制
    • 安装半同步复制插件:在主服务器和从服务器上都需要安装半同步复制插件。登录到 MySQL 客户端,执行以下命令安装插件:
INSTALL PLUGIN rpl_semi_sync_master SONAME'semisync_master.so';
INSTALL PLUGIN rpl_semi_sync_slave SONAME'semisync_slave.so';
- **启用半同步复制**:在主服务器上,启用半同步复制插件并设置等待从服务器确认的超时时间(单位为毫秒):
SET GLOBAL rpl_semi_sync_master_enabled = 1;
SET GLOBAL rpl_semi_sync_master_timeout = 10000;

在从服务器上,启用半同步复制插件:

SET GLOBAL rpl_semi_sync_slave_enabled = 1;

然后重启主从服务器的复制线程,使配置生效。在主服务器上:

STOP SLAVE IO_THREAD;
START SLAVE IO_THREAD;

在从服务器上:

STOP SLAVE;
START SLAVE;
  1. 验证半同步复制:可以通过检查 SHOW STATUS 命令的输出结果来验证半同步复制是否正常工作。在主服务器上,查看 Rpl_semi_sync_master_status 是否为 ON,以及 Rpl_semi_sync_master_wait_pos_backtraverseRpl_semi_sync_master_wait_sessions 等参数的值来了解半同步复制的运行情况。在从服务器上,查看 Rpl_semi_sync_slave_status 是否为 ON

多源复制

  1. 多源复制概念:多源复制允许一台从服务器同时从多个主服务器复制数据。这在一些复杂的数据库架构中非常有用,例如当需要整合多个独立的数据库系统的数据到一个统一的数据库中时,就可以使用多源复制。
  2. 配置多源复制:假设要从两个主服务器(Master1 和 Master2)复制数据到一个从服务器。
    • 配置每个主服务器连接:在从服务器上,分别为每个主服务器配置连接信息。例如,对于 Master1:
CHANGE MASTER TO
    MASTER_HOST='master1_ip',
    MASTER_USER='replication_user1',
    MASTER_PASSWORD='password1',
    MASTER_LOG_FILE='mysql-bin.000003',
    MASTER_LOG_POS=154
    FOR CHANNEL'master1_channel';

对于 Master2:

CHANGE MASTER TO
    MASTER_HOST='master2_ip',
    MASTER_USER='replication_user2',
    MASTER_PASSWORD='password2',
    MASTER_LOG_FILE='mysql-bin.000005',
    MASTER_LOG_POS=200
    FOR CHANNEL'master2_channel';

这里通过 FOR CHANNEL 子句为每个主服务器连接指定了一个唯一的通道名称。 - 启动多源复制:在从服务器上启动复制功能:

START SLAVE FOR CHANNEL'master1_channel';
START SLAVE FOR CHANNEL'master2_channel';
- **检查多源复制状态**:使用 `SHOW SLAVE STATUS FOR CHANNEL'master1_channel' \G` 和 `SHOW SLAVE STATUS FOR CHANNEL'master2_channel' \G` 命令分别检查每个通道的复制状态。

MySQL 复制常见问题及解决方法

复制延迟问题

  1. 原因分析
    • 网络问题:主从服务器之间的网络延迟或者带宽不足可能导致从服务器接收二进制日志的速度变慢,从而产生复制延迟。例如,主从服务器位于不同的数据中心,网络链路不稳定或者带宽有限。
    • 主服务器负载过高:如果主服务器上有大量的写操作或者复杂的查询,会导致二进制日志生成速度过快,而从服务器处理中继日志的速度跟不上。比如,在电商的促销活动期间,主服务器上大量的订单数据写入操作可能使主服务器负载过高。
    • 从服务器性能问题:从服务器的硬件配置较低,或者存在性能瓶颈,如磁盘 I/O 性能差、CPU 使用率过高,都会影响中继日志的重放速度。例如,从服务器使用的是老旧的机械硬盘,在处理大量日志重放时,磁盘 I/O 可能成为瓶颈。
    • 大事务:主服务器上执行的大事务会导致从服务器同步延迟。因为从服务器必须等待整个大事务从主服务器传输并应用完成,才能继续处理后续的事务。例如,一个包含大量数据插入的事务,在主服务器执行时间较长,从服务器同步时也会花费较长时间。
  2. 解决方法
    • 优化网络:检查主从服务器之间的网络连接,确保网络带宽足够,延迟较低。可以通过网络测试工具(如 ping、traceroute 等)排查网络问题。如果可能,优化网络拓扑结构或者升级网络设备。
    • 减轻主服务器负载:对主服务器上的查询和写操作进行优化,例如添加合适的索引,避免全表扫描,合理安排任务执行时间,避免在业务高峰期进行大量数据的导入等操作。
    • 提升从服务器性能:升级从服务器的硬件配置,如更换更快的磁盘(如 SSD),增加 CPU 核心数或内存大小。同时,优化从服务器的 MySQL 配置参数,如调整 innodb_buffer_pool_size 等参数,提高数据库性能。
    • 拆分大事务:在主服务器上,尽量将大事务拆分成多个小事务,减少单个事务的执行时间,从而降低从服务器的同步延迟。

复制中断问题

  1. 原因分析
    • 网络故障:主从服务器之间的网络连接突然中断,会导致 I/O 线程无法从主服务器获取二进制日志,从而使复制中断。例如,网络设备故障、网络配置错误等都可能引起网络中断。
    • 主服务器故障:主服务器出现硬件故障、软件崩溃或者 MySQL 服务异常重启等情况,可能导致从服务器与主服务器的连接中断,并且在主服务器恢复后,从服务器可能无法自动重新连接并恢复复制。
    • 配置错误:在配置主从复制过程中,如果参数设置错误,如主服务器的 IP 地址写错、复制用户密码错误、GTID 配置不一致等,会导致复制无法正常启动或者在运行过程中中断。
    • 数据不一致:主从服务器之间的数据出现不一致,例如在从服务器上手动修改了数据,而没有同步到主服务器,或者主从服务器之间的数据库版本、存储引擎等配置不一致,都可能导致复制中断。
  2. 解决方法
    • 处理网络故障:当网络中断后,首先检查网络连接是否恢复。如果网络恢复正常,在从服务器上执行 START SLAVE 命令尝试重新启动复制。如果复制仍然无法启动,可能需要重新配置主从连接信息,确保主服务器的 IP 地址、端口、复制用户等信息正确无误。
    • 应对主服务器故障:主服务器恢复后,需要在从服务器上检查复制状态。如果复制中断,根据主服务器的故障情况,可能需要重新设置 MASTER_LOG_FILEMASTER_LOG_POS(对于基于日志位置的复制),或者重新配置 GTID 相关信息(对于基于 GTID 的复制),然后重启从服务器的复制线程。
    • 修正配置错误:仔细检查主从服务器的配置文件和复制相关的 SQL 命令,确保所有配置参数正确。如果发现错误,及时修改并重启 MySQL 服务或者相关的复制线程,使配置生效。
    • 解决数据不一致:如果是从服务器数据被手动修改导致不一致,需要根据业务需求决定如何处理。一种方法是将从服务器的数据恢复到与主服务器一致的状态,然后重新启动复制。可以通过备份恢复或者从主服务器重新同步数据的方式来实现。如果是数据库版本、存储引擎等配置不一致,需要统一配置,确保主从服务器环境一致,然后重新配置复制。

主从数据不一致问题

  1. 原因分析
    • 手动操作差异:在主从服务器上分别进行了不同的手动数据操作,例如在主服务器上插入了一条数据,而在从服务器上删除了同一条数据,或者在从服务器上直接修改了数据,而没有通过主服务器进行同步操作。
    • 存储引擎差异:主从服务器使用了不同的存储引擎,不同存储引擎在处理数据时可能存在一些细微的差异,例如在处理 NULL 值、索引等方面,可能导致数据不一致。
    • 版本差异:主从服务器的 MySQL 版本不同,一些新特性或者 bug 修复在不同版本中有所不同,可能会影响数据的处理和存储,从而导致数据不一致。
    • 复制过滤规则:如果配置了复制过滤规则,可能会导致部分数据在主从服务器之间同步不一致。例如,设置了只同步某些数据库或者表,而在实际操作中,对不在同步范围内的数据库或表进行了数据修改。
  2. 解决方法
    • 避免手动操作差异:严格限制在从服务器上进行手动数据操作,所有的数据修改都应该通过主服务器进行,以确保数据的一致性。如果已经出现手动操作差异,需要根据业务逻辑将数据恢复到一致状态。可以通过备份恢复、数据对比工具等方式来找出差异并进行修复。
    • 统一存储引擎:检查主从服务器的存储引擎配置,确保使用相同的存储引擎。如果不一致,需要将存储引擎统一。可以通过修改表的存储引擎来实现,例如:
ALTER TABLE your_table_name ENGINE = InnoDB;

注意在修改存储引擎之前,需要备份数据以防万一。 - 统一版本:尽量使主从服务器的 MySQL 版本保持一致。如果版本不一致,需要了解不同版本之间的差异,并针对可能影响数据一致性的问题进行评估和处理。在条件允许的情况下,将主从服务器升级或降级到相同的版本。 - 检查复制过滤规则:仔细检查复制过滤规则,确保其符合业务需求并且不会导致数据同步异常。如果发现过滤规则有误,及时调整。同时,在进行数据操作时,要注意操作的数据库和表是否在复制过滤的范围内。

从服务器 I/O 线程或 SQL 线程异常问题

  1. 原因分析
    • 权限问题:从服务器的复制用户权限不足,可能导致 I/O 线程无法连接到主服务器获取二进制日志,或者 SQL 线程在执行中继日志中的操作时没有足够的权限。例如,复制用户没有 REPLICATION SLAVE 权限,或者在某些情况下,对特定数据库或表的操作权限不足。
    • 日志文件损坏:主服务器的二进制日志文件或者从服务器的中继日志文件可能损坏,导致 I/O 线程无法正确读取二进制日志,或者 SQL 线程无法正确重放中继日志。例如,磁盘故障、文件系统错误等可能导致日志文件损坏。
    • 锁争用:在从服务器上,SQL 线程在重放中继日志时,可能会遇到锁争用问题,导致线程阻塞或异常。例如,当从服务器上有大量并发的读操作,而 SQL 线程需要对某些表进行写操作时,可能会发生锁争用。
  2. 解决方法
    • 检查权限:确保从服务器的复制用户具有正确的权限。可以在从服务器上重新授予 REPLICATION SLAVE 权限,并检查对相关数据库和表的操作权限。例如:
GRANT REPLICATION SLAVE ON *.* TO'replication_user'@'%';
FLUSH PRIVILEGES;
- **修复日志文件**:如果怀疑日志文件损坏,可以尝试使用 MySQL 提供的工具进行修复。对于二进制日志文件,可以使用 `mysqlbinlog` 工具查看日志内容,检查是否存在错误。对于中继日志文件,可以尝试删除损坏的中继日志文件(注意不要删除正在使用的中继日志文件),然后重启从服务器的 I/O 线程,从服务器会重新获取主服务器的二进制日志并生成新的中继日志文件。
- **处理锁争用**:优化从服务器上的查询和写操作,尽量减少锁争用的发生。例如,合理调整事务隔离级别,避免长时间持有锁;对经常发生锁争用的表进行优化,如添加合适的索引等。同时,可以通过 `SHOW ENGINE INNODB STATUS` 命令查看 InnoDB 引擎的状态,了解锁争用的具体情况,以便针对性地进行优化。

通过对以上 MySQL 复制技术的全面了解以及常见问题的解决方法,能够帮助我们构建更加稳定、可靠且高效的数据库复制环境,满足不同业务场景下的数据冗余、读扩展以及高可用性等需求。在实际应用中,需要根据具体的业务需求和系统架构,灵活选择合适的复制拓扑结构和复制机制,并及时处理可能出现的各种问题,以确保数据的一致性和系统的稳定性。