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

MySQL复制常见问题与解决方案汇总

2021-04-143.8k 阅读

MySQL 复制简介

MySQL 复制是一种数据备份和高可用性解决方案,它允许将数据从一个 MySQL 数据库服务器(主服务器)复制到一个或多个其他 MySQL 数据库服务器(从服务器)。这种机制基于主服务器记录数据库更改的二进制日志(binary log),从服务器通过读取并应用这些日志来保持与主服务器数据的同步。

复制的基本原理

  1. 主服务器:每当主服务器上执行了修改数据的 SQL 语句(如 INSERT、UPDATE、DELETE),这些更改会被记录到二进制日志(binlog)中。每个更改在 binlog 中被记录为一个事件(event)。
  2. 从服务器:从服务器有两个线程来处理复制过程,即 I/O 线程和 SQL 线程。I/O 线程连接到主服务器,请求主服务器发送 binlog 中的事件,并将这些事件写入从服务器的中继日志(relay log)。SQL 线程则负责读取中继日志,并按顺序执行其中的事件,从而使从服务器的数据与主服务器保持一致。

常见问题及解决方案

网络连接问题

  1. 从服务器无法连接到主服务器
    • 问题描述:在配置从服务器时,使用 CHANGE MASTER TO 语句设置主服务器连接信息后,启动从服务器复制,出现 ERROR 1203 (HY000): The server is not configured as slave; fix in config file or with CHANGE MASTER TO 等错误,且从服务器的 SHOW SLAVE STATUS \G 结果中 Slave_IO_RunningNo
    • 原因分析
      • 网络问题,主从服务器之间网络不通,可能是防火墙、网络配置等原因。
      • 主服务器配置错误,如 bind - address 配置限制了主服务器只能监听本地连接,导致从服务器无法连接。
      • 主服务器账号密码错误,在 CHANGE MASTER TO 语句中设置的主服务器连接账号密码不正确。
    • 解决方案
      • 检查网络:使用 ping 命令测试主从服务器之间的网络连通性,确保能够互相 ping 通。如果不通,检查防火墙规则,开放主从服务器之间用于 MySQL 复制的端口(默认为 3306)。例如,在 Linux 系统中,使用 iptables -I INPUT -p tcp --dport 3306 -j ACCEPT 命令允许 3306 端口的 TCP 连接。
      • 检查主服务器配置:编辑主服务器的 my.cnf 文件,确保 bind - address 配置为允许从服务器连接的 IP 地址(如果设置为 127.0.0.1 则只能本地连接),或者直接注释掉该配置行,使 MySQL 监听所有可用的网络接口。修改配置后重启 MySQL 服务。
      • 检查账号密码:确认 CHANGE MASTER TO 语句中的主服务器账号密码正确。可以在主服务器上使用 GRANT REPLICATION SLAVE ON *.* TO'slave_user'@'slave_host' IDENTIFIED BY 'password'; 重新创建或修改用于复制的账号,并在从服务器上重新执行 CHANGE MASTER TO 语句,例如:
CHANGE MASTER TO
    MASTER_HOST='master_host_ip',
    MASTER_USER='slave_user',
    MASTER_PASSWORD='password',
    MASTER_LOG_FILE='master_binlog_file',
    MASTER_LOG_POS=master_binlog_position;
  1. 网络波动导致复制中断
    • 问题描述:复制过程中,由于网络不稳定,出现短暂中断,导致从服务器复制停止,SHOW SLAVE STATUS \G 结果中 Slave_IO_Running 变为 No,且有类似 Got fatal error 1236 from master when reading data from binary log: 'Could not find first log file name in binary log index file' 的错误信息。
    • 原因分析:网络波动导致从服务器的 I/O 线程与主服务器的连接中断,在重新连接时,可能无法正确定位主服务器的二进制日志位置。
    • 解决方案
      • 自动重连设置:在从服务器的 my.cnf 文件中,可以设置 slave_net_timeout 参数,该参数定义了从服务器 I/O 线程等待主服务器响应的超时时间(默认值为 3600 秒)。适当调整该值,例如设置为 60 秒,可使从服务器在网络短暂中断后更快地尝试重新连接。
[mysqld]
slave_net_timeout = 60

修改配置后重启 MySQL 服务。 - 手动修复:如果自动重连失败,可以手动重新启动从服务器的复制。首先查看主服务器的二进制日志状态,获取当前的二进制日志文件名和位置:

SHOW MASTER STATUS;

然后在从服务器上使用 CHANGE MASTER TO 语句重新设置主服务器连接信息,使用获取到的主服务器二进制日志文件名和位置:

CHANGE MASTER TO
    MASTER_HOST='master_host_ip',
    MASTER_USER='slave_user',
    MASTER_PASSWORD='password',
    MASTER_LOG_FILE='new_master_binlog_file',
    MASTER_LOG_POS=new_master_binlog_position;
START SLAVE;

数据一致性问题

  1. 主从数据不一致
    • 问题描述:在复制过程中,发现主服务器和从服务器上的数据出现不一致,例如相同表中的记录数量不同,或者某些记录的值不同。
    • 原因分析
      • 主服务器上执行非事务性语句:如果在主服务器上执行了非事务性的 DDL 语句(如 CREATE TABLEALTER TABLE),且在执行过程中主服务器崩溃,可能导致主从数据不一致。因为从服务器可能只应用了部分 DDL 操作。
      • 存储引擎特性:某些存储引擎(如 MyISAM)不支持事务,在主服务器上对 MyISAM 表进行并发写入时,可能由于写入顺序不同导致主从数据不一致。
      • 主从服务器版本差异:不同版本的 MySQL 在复制某些操作时可能存在兼容性问题,导致数据不一致。
    • 解决方案
      • 使用事务:尽量在主服务器上使用支持事务的存储引擎(如 InnoDB),并且对于可能影响数据一致性的操作,使用事务进行包裹。例如:
START TRANSACTION;
-- 执行一系列 SQL 操作
INSERT INTO table_name (column1, column2) VALUES ('value1', 'value2');
UPDATE table_name SET column1 = 'new_value' WHERE condition;
DELETE FROM table_name WHERE another_condition;
COMMIT;
    - **版本一致性**:确保主从服务器的 MySQL 版本一致,或者参考 MySQL 官方文档,了解不同版本间复制的兼容性问题,并进行相应的调整。
    - **数据校验与修复**:可以使用工具如 `pt - table - checksum` 来校验主从服务器的数据一致性。该工具会在主服务器上计算表的校验和,并将结果发送到从服务器进行对比。如果发现不一致,可以使用 `pt - table - sync` 工具进行修复。例如,安装 Percona Toolkit 后,在主服务器上执行:
pt - table - checksum --nocheck - binlog - format h=master_host_ip,u=checksum_user,p=password,D=database_name,t=table_name

在从服务器上执行修复命令:

pt - table - sync --execute h=master_host_ip,u=sync_user,p=password h=slave_host_ip,u=sync_user,p=password D=database_name,t=table_name
  1. 从服务器延迟
    • 问题描述:从服务器的复制出现延迟,SHOW SLAVE STATUS \G 结果中 Seconds_Behind_Master 显示的值较大,表明从服务器的数据落后于主服务器。
    • 原因分析
      • 主服务器负载过高:主服务器上有大量的写入操作,导致二进制日志生成速度过快,从服务器的 I/O 线程和 SQL 线程来不及处理。
      • 从服务器性能问题:从服务器的硬件资源(如 CPU、内存、磁盘 I/O)不足,无法快速处理中继日志中的事件。
      • 大事务:主服务器上执行了大事务,从服务器需要花费较长时间来应用这些事务。
    • 解决方案
      • 优化主服务器负载:分析主服务器的负载情况,优化查询语句,减少不必要的写入操作。可以使用 SHOW PROCESSLIST 查看当前主服务器上执行的查询,找出性能瓶颈并进行优化。
      • 提升从服务器性能:检查从服务器的硬件资源使用情况,根据需要增加 CPU、内存或优化磁盘 I/O。例如,可以调整 MySQL 的缓冲池大小(innodb_buffer_pool_size)来提高内存使用效率。
      • 并行复制:从 MySQL 5.6 开始支持并行复制,可以通过设置 slave_parallel_workers 参数启用并行复制,使从服务器的 SQL 线程能够并行应用中继日志中的事件,从而提高复制速度。在从服务器的 my.cnf 文件中添加:
[mysqld]
slave_parallel_workers = 4

修改配置后重启 MySQL 服务。同时,还可以设置 slave_parallel_type 参数来指定并行复制的类型,如 DATABASE(按数据库并行)或 LOGICAL_CLOCK(基于逻辑时钟并行)。 - 大事务拆分:尽量避免在主服务器上执行大事务,将大事务拆分成多个小事务执行,以减少从服务器应用事务的时间。

权限和配置问题

  1. 权限不足
    • 问题描述:在从服务器上启动复制时,出现 ERROR 1045 (28000): Access denied for user'slave_user'@'slave_host' (using password: YES) 错误。
    • 原因分析:用于复制的账号在主服务器上没有足够的权限。
    • 解决方案:在主服务器上,使用具有足够权限的账号登录 MySQL,然后为复制账号授予 REPLICATION SLAVE 权限,例如:
GRANT REPLICATION SLAVE ON *.* TO'slave_user'@'slave_host' IDENTIFIED BY 'password';
FLUSH PRIVILEGES;
  1. 配置参数错误
    • 问题描述:复制过程中出现各种奇怪的错误,如 ERROR 1872 (HY000): Slave failed to initialize relay log info structure from the repository 等,可能与配置参数有关。
    • 原因分析:MySQL 配置文件(my.cnf)中的参数设置错误,例如 log - binserver - id 等参数配置不正确。
    • 解决方案
      • 检查 log - bin 配置:在主服务器上,确保 log - bin 参数已正确配置,且指定了二进制日志文件的路径和前缀。例如:
[mysqld]
log - bin = /var/log/mysql/mysql - bin
    - **检查 `server - id` 配置**:主从服务器的 `server - id` 必须唯一,且为正整数。在主服务器和从服务器的 `my.cnf` 文件中分别设置不同的 `server - id`,例如:
# 主服务器
[mysqld]
server - id = 1

# 从服务器
[mysqld]
server - id = 2

修改配置后重启 MySQL 服务。

二进制日志和中继日志问题

  1. 二进制日志损坏
    • 问题描述:主服务器的二进制日志文件损坏,导致从服务器无法正确读取和应用日志,出现 ERROR 1236 (HY000): Could not find first log file name in binary log index file 等错误。
    • 原因分析
      • 磁盘故障,导致二进制日志文件在写入过程中损坏。
      • MySQL 服务异常终止,可能导致二进制日志文件没有正确关闭。
    • 解决方案
      • 备份与恢复:如果有二进制日志备份,可以使用备份文件进行恢复。首先停止主服务器的 MySQL 服务,将备份的二进制日志文件复制到主服务器的二进制日志目录(根据 log - bin 参数配置),然后重启 MySQL 服务。
      • 重建二进制日志:如果没有备份,可以尝试重建二进制日志。在主服务器上,停止 MySQL 服务,删除损坏的二进制日志文件和索引文件(通常位于 log - bin 参数指定的目录下,索引文件名为 mysql - bin.index)。然后重启 MySQL 服务,MySQL 会重新生成新的二进制日志文件。接下来,需要在从服务器上重新设置主服务器连接信息,使用 CHANGE MASTER TO 语句指定新的二进制日志文件名和位置(通过 SHOW MASTER STATUS 在主服务器上获取)。
  2. 中继日志清理问题
    • 问题描述:从服务器的中继日志不断增长,占用大量磁盘空间。
    • 原因分析:默认情况下,从服务器不会自动清理中继日志,只有在执行 RESET SLAVESTOP SLAVE 后,中继日志才会被删除。
    • 解决方案
      • 自动清理:可以通过设置 relay_log_purge 参数为 1(默认值为 1)来启用自动清理中继日志功能。在从服务器的 my.cnf 文件中添加或确认该配置:
[mysqld]
relay_log_purge = 1

修改配置后重启 MySQL 服务。 - 手动清理:如果不想启用自动清理,也可以手动清理中继日志。在确保从服务器复制正常运行且不需要使用中继日志进行恢复的情况下,执行 PURGE RELAY LOGS TO'relay - log - name'; 语句来删除指定中继日志文件及之前的所有中继日志文件。例如:

PURGE RELAY LOGS TO'mysql - relay - bin.000010';

复制拓扑相关问题

  1. 链式复制中的问题
    • 问题描述:在链式复制拓扑(主服务器 -> 从服务器1 -> 从服务器2)中,从服务器2出现复制异常,如 Slave_IO_RunningNo 或数据不一致。
    • 原因分析
      • 从服务器1出现问题,如网络中断、数据一致性问题等,导致无法正常向从服务器2传递二进制日志。
      • 从服务器2与从服务器1的连接配置错误,如账号密码、二进制日志位置等设置不正确。
    • 解决方案
      • 检查从服务器1:首先检查从服务器1的状态,确保其与主服务器的复制正常,SHOW SLAVE STATUS \G 结果中各项参数正常。如果从服务器1与主服务器存在数据一致性问题,按照前面数据一致性问题的解决方案进行修复。同时,检查从服务器1的网络连接,确保其能够正常与主服务器和从服务器2通信。
      • 检查从服务器2配置:确认从服务器2与从服务器1的连接配置正确。使用 CHANGE MASTER TO 语句重新设置从服务器2连接从服务器1的信息,例如:
CHANGE MASTER TO
    MASTER_HOST='slave1_host_ip',
    MASTER_USER='slave2_user',
    MASTER_PASSWORD='password',
    MASTER_LOG_FILE='slave1_binlog_file',
    MASTER_LOG_POS=slave1_binlog_position;
START SLAVE;
  1. 双活或多活复制中的冲突问题
    • 问题描述:在双活或多活复制拓扑中,多个主服务器同时写入数据,导致数据冲突,出现复制错误。
    • 原因分析:多个主服务器在没有协调机制的情况下同时写入相同的数据,例如在不同主服务器上对同一行数据进行更新操作,导致复制过程中出现冲突。
    • 解决方案
      • 使用分布式事务:可以引入分布式事务框架(如 XA 事务)来确保多个主服务器之间的数据一致性。在执行涉及多个主服务器的写入操作时,通过分布式事务框架协调各个主服务器的事务,保证要么所有操作都成功,要么都失败。
      • 数据分区:对数据进行分区,每个主服务器负责特定分区的数据写入。例如,按照业务模块或数据范围进行分区,不同主服务器只处理自己分区内的数据,避免同时写入相同数据导致的冲突。
      • 同步机制:建立同步机制,使多个主服务器之间在写入数据前进行同步。例如,可以使用 ZooKeeper 等分布式协调服务来实现主服务器之间的同步,确保同一时间只有一个主服务器可以写入特定数据。

其他问题

  1. 字符集问题
    • 问题描述:主从服务器之间字符集不一致,导致数据在复制过程中出现乱码或错误。
    • 原因分析:主从服务器的字符集配置不同,例如主服务器使用 utf8mb4 字符集,而从服务器使用 utf8 字符集,当主服务器上存储的特殊字符(如 emoji 等)复制到从服务器时,可能会出现乱码。
    • 解决方案
      • 统一字符集:确保主从服务器的字符集一致。可以在主从服务器的 my.cnf 文件中设置相同的字符集,例如:
[mysqld]
character - set - server = utf8mb4
collation - server = utf8mb4_unicode_ci

修改配置后重启 MySQL 服务。同时,还需要检查数据库和表的字符集设置,确保与服务器字符集一致。可以使用以下语句修改数据库字符集:

ALTER DATABASE database_name CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

修改表字符集:

ALTER TABLE table_name CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
  1. 存储过程和函数问题
    • 问题描述:在主服务器上创建或修改存储过程和函数后,从服务器复制出现错误,如 ERROR 1418 (HY000): This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its declaration and binary logging is enabled (you *might* want to use the less safe log_bin_trust_function_creators variable)
    • 原因分析:MySQL 在二进制日志记录存储过程和函数时,要求这些存储过程和函数具有 DETERMINISTIC(确定性)、NO SQL(无 SQL 语句)或 READS SQL DATA(只读 SQL 语句)属性,否则在二进制日志记录和复制过程中可能出现问题。
    • 解决方案
      • 修改存储过程和函数声明:在创建或修改存储过程和函数时,确保添加适当的属性。例如,对于确定性的存储过程:
DELIMITER //
CREATE DEFINER = 'user'@'host' PROCEDURE procedure_name()
DETERMINISTIC
BEGIN
    -- 存储过程逻辑
END //
DELIMITER ;
    - **设置 `log_bin_trust_function_creators`**:如果无法修改存储过程和函数的声明,可以在主从服务器上设置 `log_bin_trust_function_creators` 参数为 `1`,允许创建不具备上述属性的存储过程和函数,但这种方法存在一定风险,因为可能导致二进制日志记录不准确。在主从服务器的 `my.cnf` 文件中添加:
[mysqld]
log_bin_trust_function_creators = 1

修改配置后重启 MySQL 服务。

通过对以上常见问题的分析和解决方案的了解,能够帮助数据库管理员更好地维护 MySQL 复制环境,确保数据的一致性和高可用性。在实际应用中,还需要根据具体的业务场景和系统架构,灵活运用这些方法来解决遇到的问题。同时,定期对 MySQL 复制进行监控和优化,也是保障系统稳定运行的重要措施。例如,可以使用 SHOW SLAVE STATUS 命令定期检查从服务器的复制状态,及时发现并处理可能出现的问题。另外,备份策略的制定也不容忽视,以便在出现严重问题时能够快速恢复数据。对于复杂的复制拓扑,如多主多从结构,需要更加谨慎地进行配置和管理,确保各个节点之间的数据同步准确无误。在数据库升级或更换版本时,要提前做好兼容性测试,避免因版本差异导致复制出现问题。总之,MySQL 复制是一个强大的功能,但需要细心维护和管理,以充分发挥其在数据备份和高可用性方面的优势。