三亩地 三亩地SAN MU DI · CODE DIARY
ARTICLE DETAIL

日记详情

真实记录编程学习的某一天,欢迎挑你感兴趣的翻一翻。

MySQL主从复制实战:从零搭建高可用与读写分离架构

MySQL主从复制实战:从零搭建高可用与读写分离架构

1. 项目缘起:为什么我们需要MySQL主从复制?

在数据库运维和开发工作中,数据的高可用性和读写分离是绕不开的话题。想象一下,你的应用只有一个MySQL数据库,它既是所有用户查询的入口,也是所有数据写入的终点。当业务量不大时,这没什么问题。但随着用户增长,你会发现,一个简单的报表查询可能就会拖慢整个应用的响应速度,因为它在和核心交易争抢同一份计算和I/O资源。更糟糕的是,如果这台唯一的数据库服务器因为硬件故障、机房断电或者一次不小心的误操作而宕机,你的整个服务就彻底中断了,数据恢复的RTO(恢复时间目标)和RPO(恢复点目标)都变得不可控。

这就是MySQL主从复制(Master-Slave Replication)要解决的核心问题。它不是一项高深莫测的技术,而是每个后端工程师和DBA都应该掌握的“生存技能”。简单来说,主从复制就是让一台MySQL服务器(主库)上的数据变更,自动地、异步地同步到另一台或多台MySQL服务器(从库)上。这样一来,从库就可以承担起读请求的压力,实现读写分离,提升整体性能;同时,从库也作为主库的一个实时备份,在主库发生故障时,可以快速切换,保障服务不中断。

我经历过不止一次因为单点数据库故障导致的线上事故,也见证过在引入主从架构后,系统稳定性和性能的显著提升。今天,我就从一个实践者的角度,带你从零开始,手把手搭建一套MySQL主从复制环境,并深入探讨在实际使用中会遇到的各种“坑”和最佳实践。无论你是刚接触MySQL的新手,还是想系统梳理一下这块知识的老兵,相信这篇内容都能给你带来实实在在的收获。

2. 环境准备与核心概念澄清

在动手搭建之前,我们必须把“战场”打扫干净,并理解清楚我们要操作的几个核心角色。很多人搭建失败,第一步就栽在了环境混乱和概念模糊上。

2.1 服务器规划与基础环境

理论上,主库和从库可以部署在同一台机器的不同端口,但这在生产环境中没有意义,失去了高可用的价值。我们假设一个最典型的生产级最小化场景:

  • 主库 (Master): 一台独立的服务器,IP:192.168.1.100, 我们使用默认的MySQL端口3306
  • 从库 (Slave): 另一台独立的服务器,IP:192.168.1.101, 同样使用端口3306

注意:两台服务器的MySQL版本应尽可能保持一致,尤其是大版本(如8.0.x)。混合大版本(如5.7主库,8.0从库)可能会因语法、默认配置或复制格式的差异导致不可预知的问题。建议都使用MySQL 8.0的最新稳定版。

首先,在两台服务器上分别安装MySQL。这里以CentOS 7为例,使用YUM安装:

# 1. 下载并安装MySQL官方的YUM仓库 sudo yum install -y https://dev.mysql.com/get/mysql80-community-release-el7-11.noarch.rpm # 2. 安装MySQL服务器 sudo yum install -y mysql-community-server # 3. 启动MySQL服务并设置开机自启 sudo systemctl start mysqld sudo systemctl enable mysqld

安装完成后,MySQL会为root用户生成一个临时密码,位于日志文件中:

sudo grep 'temporary password' /var/log/mysqld.log

使用该密码登录,并立即修改为一个强密码:

mysql -u root -p # 输入临时密码 ALTER USER 'root'@'localhost' IDENTIFIED BY 'YourNewStrongPassword123!';

2.2 理解复制中的三个关键线程

这是理解主从复制工作原理的基石。很多教程只教配置,不讲原理,导致出了问题无从排查。

  1. Binlog Dump Thread (主库): 当有从库连接上来时,主库会为每个连接的从库创建一个Binlog Dump线程。这个线程的唯一职责就是读取主库的二进制日志(Binary Log)中的事件,并将其发送给从库的I/O线程。你可以通过在主库执行SHOW PROCESSLIST;看到一个Binlog Dump线程,其State通常为Master has sent all binlog to slave; waiting for more updates

  2. I/O Thread (从库): 从库上的I/O线程负责连接到主库,并向主库的Binlog Dump线程发起请求,接收主库发送过来的二进制日志事件。然后,它会将这些事件写入从库本地的中继日志(Relay Log)文件中。在从库执行SHOW SLAVE STATUS\GSlave_IO_Running这个状态就反映了I/O线程是否在正常运行。

  3. SQL Thread (从库): 从库上的SQL线程负责读取本地的中继日志(Relay Log),并解析、重放其中记录的SQL事件(或行变更),从而让从库的数据与主库保持一致。同样在SHOW SLAVE STATUS\G中,Slave_SQL_Running状态反映了SQL线程的运行情况。

一个健康的主从复制,必须是Slave_IO_Running: YesSlave_SQL_Running: Yes任何一个为NoConnecting,都意味着复制中断了。

2.3 必须搞清的日志文件:Binlog 和 Relay Log

  • 二进制日志 (Binary Log, Binlog): 这是主从复制的“源头活水”。主库上所有会修改数据的SQL语句(DDL、DML)或行数据的变更,都会以“事件”的形式按顺序记录在Binlog中。Binlog不仅用于复制,也用于数据恢复。它有三种格式:STATEMENT(基于SQL语句)、ROW(基于数据行变化)、MIXED(混合模式)。MySQL 8.0 默认使用ROW格式,这是最安全、最推荐的方式,能最大程度保证主从数据一致性。

  • 中继日志 (Relay Log): 你可以把它理解为从库的“收件箱”。从库的I/O线程从主库拉取到的Binlog事件,并不会直接执行,而是先原封不动地写入本地的Relay Log文件。然后,SQL线程再从Relay Log中读取事件来执行。这样的设计实现了“接收”和“执行”的解耦,提供了缓冲,也使得从库可以在复制中断后,从断点继续拉取,而不必重新全量同步。

理解了这些,我们再开始配置,你就会清楚每一步是在做什么,而不是机械地复制命令。

3. 主库(Master)配置详解

主库的配置核心是:开启Binlog,设置一个唯一的服务器ID,并创建一个专门用于复制的用户。

3.1 修改MySQL配置文件

编辑主库服务器(192.168.1.100)上的MySQL配置文件,通常是/etc/my.cnf/etc/mysql/my.cnf.d/mysqld.cnf(取决于你的系统和安装方式)。

[mysqld]部分添加或修改以下配置:

[mysqld] # 服务器唯一ID,这是必须的,主从不能相同 server-id = 100 # 启用二进制日志,并指定日志文件的前缀 log-bin = mysql-bin # 设置二进制日志格式,ROW模式是8.0的默认值,也是最佳实践 binlog-format = ROW # 可选:指定哪些数据库需要记录Binlog。不配置则记录所有。 # binlog-do-db = your_database_name # 可选:指定哪些数据库不需要记录Binlog。 # binlog-ignore-db = mysql, sys, information_schema, performance_schema

关键参数解析:

  • server-id=100: 我习惯用IP地址的最后一段作为ID,方便识别。只要保证主从网络内所有MySQL实例的server-id唯一即可。
  • log-bin=mysql-bin: 开启了二进制日志,日志文件将以mysql-bin.000001,mysql-bin.000002这样的序列命名。
  • binlog-format=ROW: 这是最重要的设置之一。在ROW格式下,Binlog记录的是每一行数据修改前后的镜像。例如,一条UPDATE语句更新了1000行,在STATEMENT格式下只记录这条SQL语句本身,而在ROW格式下会记录这1000行数据的变化。虽然日志量更大,但它不依赖于SQL上下文(如触发器、存储过程、自定义函数),能最精确地保证主从数据一致。生产环境强烈建议使用ROW格式。

配置完成后,重启MySQL服务使配置生效:

sudo systemctl restart mysqld

3.2 创建复制专用账户

出于安全考虑,我们不应该让从库直接用root账户连接主库。需要创建一个权限受限的专用账户。

登录主库MySQL:

mysql -u root -p

执行以下SQL:

-- 创建一个用户名为`repl`,允许从`192.168.1.101`(从库IP)登录的用户 CREATE USER 'repl'@'192.168.1.101' IDENTIFIED BY 'StrongReplPassword123!'; -- 授予该用户复制所需的权限。 -- REPLICATION SLAVE 权限允许该用户连接主库并请求Binlog。 GRANT REPLICATION SLAVE ON *.* TO 'repl'@'192.168.1.101'; -- 刷新权限,使授权立即生效 FLUSH PRIVILEGES;

实操心得:这里'repl'@'192.168.1.101'限制了该用户只能从指定的从库IP登录,更安全。如果你的从库IP可能变化,或者有多个从库,可以使用'repl'@'192.168.1.%'(允许整个网段)或'repl'@'%'(允许任何主机,不推荐)。密码务必设置得足够复杂。

3.3 锁定主库并获取初始状态

为了确保从库从一个一致性的数据快照开始同步,我们需要暂时阻止主库新的数据写入,并记录下当前的Binlog位置。

-- 1. 全局读锁,阻止所有新的数据写入(DML)和表结构变更(DDL)。 FLUSH TABLES WITH READ LOCK; -- 2. 查看当前的Binlog文件名称和位置。请务必记录下 File 和 Position 的值! SHOW MASTER STATUS;

执行SHOW MASTER STATUS;你会看到类似下面的输出:

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

记下File: mysql-bin.000003Position: 785。这告诉从库:“请从mysql-bin.000003这个文件的第785个字节之后开始复制。”

现在,保持这个MySQL会话窗口打开,不要退出,也不要执行UNLOCK TABLES。锁还在生效。我们需要在另一个终端窗口,对主库的数据进行备份。

4. 数据备份与从库(Slave)初始化

主库锁住后,数据是静止的。我们需要将这个静止状态的数据完整地迁移到从库。

4.1 使用mysqldump备份主库数据

打开一个新的终端,连接到主库服务器,使用mysqldump工具进行全量备份。这里我们备份所有数据库(排除系统库):

# 在主库服务器上执行 mysqldump -u root -p --all-databases \ --master-data=2 \ # 这个选项会在导出的SQL文件中,以CHANGE MASTER TO注释的形式包含主库的Binlog位置信息 --single-transaction \ # 对于InnoDB表,开启一个事务来确保数据一致性,与`--master-data`一起使用时,会自动禁用`--lock-tables` --routines \ # 备份存储过程和函数 --triggers \ # 备份触发器 --events > /tmp/master_full_backup.sql

输入root密码后,备份文件会保存在/tmp/master_full_backup.sql

参数详解:

  • --master-data=2: 这是关键。它会在输出的SQL文件中添加一行注释,例如-- CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000003', MASTER_LOG_POS=785;。这样我们在从库导入时,可以方便地获取起始位置。=2表示这行命令被注释掉,不会自动执行。
  • --single-transaction: 对InnoDB表进行非阻塞的备份,通过启动一个事务来获取一致性视图。这是在线备份InnoDB的推荐方式,避免了长时间锁表。
  • --routines --triggers --events: 确保存储过程、触发器、事件等对象也被备份。

备份完成后,回到之前那个锁表的MySQL会话窗口,释放锁:

UNLOCK TABLES;

现在主库可以恢复正常写入了。

4.2 传输备份文件并导入从库

将备份文件从主库复制到从库(192.168.1.101):

# 在主库执行 scp /tmp/master_full_backup.sql root@192.168.1.101:/tmp/

然后,登录从库服务器,将备份数据导入:

# 在从库服务器上执行 mysql -u root -p < /tmp/master_full_backup.sql

这个过程可能会比较长,取决于数据库的大小。导入完成后,从库就拥有了和主库在锁表时刻完全一致的数据。

4.3 配置从库并启动复制

现在,我们来配置从库,告诉它:谁是主库,用什么账号连接,以及从哪里开始复制。

首先,编辑从库的MySQL配置文件/etc/my.cnf

[mysqld] # 服务器唯一ID,必须与主库不同 server-id = 101 # 从库也可以开启binlog,这在它作为其他从库的主库(级联复制)或需要做数据恢复时有用 log-bin = mysql-bin # 可选:设置中继日志文件的前缀 relay-log = mysql-relay-bin # 可选:设置从库的更新是否写入自身的binlog。LOG_SLAVE_UPDATES=1表示写入,这在级联复制中是必须的。 # log-slave-updates = 1 # 可选:防止从库被意外写入(只读模式)。强烈建议开启! read-only = 1
  • server-id=101: 确保与主库不同。
  • read-only=1:这是一个非常重要的安全设置。它使得从库普通用户(非super权限)只能进行读操作,不能写入。这可以防止应用误操作或程序BUG导致数据写入从库,造成主从数据不一致。但root用户依然可以写。

重启从库MySQL服务:

sudo systemctl restart mysqld

登录从库MySQL,执行关键的CHANGE MASTER TO命令:

mysql -u root -p
-- 停止从库复制线程(如果是首次配置,它们本来就是停止的) STOP SLAVE; -- 配置主库连接信息 CHANGE MASTER TO MASTER_HOST = '192.168.1.100', -- 主库IP MASTER_USER = 'repl', -- 主库上创建的复制用户 MASTER_PASSWORD = 'StrongReplPassword123!', -- 复制用户密码 MASTER_PORT = 3306, -- 主库端口 MASTER_LOG_FILE = 'mysql-bin.000003', -- 之前记录的File MASTER_LOG_POS = 785, -- 之前记录的Position MASTER_CONNECT_RETRY = 60; -- 连接失败后重试间隔(秒) -- 启动从库复制线程 START SLAVE;

这里有一个非常重要的技巧:如果你在备份时使用了--master-data=2,其实可以不用手动去记FilePosition。你可以用以下命令从备份文件中提取:

head -n 100 /tmp/master_full_backup.sql | grep "CHANGE MASTER TO"

输出结果中的MASTER_LOG_FILEMASTER_LOG_POS就是你需要填写的值。

5. 验证与监控:你的复制真的成功了吗?

执行完START SLAVE;后,复制并不会立刻完成。你需要检查从库的复制状态。

5.1 使用SHOW SLAVE STATUS进行深度诊断

这是监控主从复制最核心的命令。执行SHOW SLAVE STATUS\G\G使结果垂直显示,更易读)。

你会看到非常多的字段,我们聚焦几个最关键的:

*************************** 1. row *************************** Slave_IO_State: Waiting for master to send event Master_Host: 192.168.1.100 Master_User: repl Master_Port: 3306 Connect_Retry: 60 Master_Log_File: mysql-bin.000003 Read_Master_Log_Pos: 785 Relay_Log_File: mysql-relay-bin.000002 Relay_Log_Pos: 320 Relay_Master_Log_File: mysql-bin.000003 Slave_IO_Running: Yes Slave_SQL_Running: Yes Replicate_Do_DB: Replicate_Ignore_DB: Replicate_Do_Table: Replicate_Ignore_Table: Replicate_Wild_Do_Table: Replicate_Wild_Ignore_Table: Last_Errno: 0 Last_Error: Skip_Counter: 0 Exec_Master_Log_Pos: 785 Relay_Log_Space: 526 Until_Condition: None Until_Log_File: Until_Log_Pos: 0 Master_SSL_Allowed: No Master_SSL_CA_File: Master_SSL_CA_Path: Master_SSL_Cert: Master_SSL_Cipher: Master_SSL_Key: Seconds_Behind_Master: 0 Master_SSL_Verify_Server_Cert: No Last_IO_Errno: 0 Last_IO_Error: Last_SQL_Errno: 0 Last_SQL_Error: Replicate_Ignore_Server_Ids: Master_Server_Id: 100 Master_UUID: f6a16b8e-d3a7-11ed-9c7b-000c29a4b4e2 Master_Info_File: mysql.slave_master_info SQL_Delay: 0 SQL_Remaining_Delay: NULL Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates Master_Retry_Count: 86400 Master_Bind: Last_IO_Error_Timestamp: Last_SQL_Error_Timestamp: Master_SSL_Crl: Master_SSL_Crlpath: Retrieved_Gtid_Set: Executed_Gtid_Set: Auto_Position: 0 Replicate_Rewrite_DB: Channel_Name: Master_TLS_Version: Master_public_key_path: Get_master_public_key: 0 Network_Namespace:

成功运行的黄金标准:

  1. Slave_IO_Running: Yes— I/O线程正在运行,正在从主库拉取日志。
  2. Slave_SQL_Running: Yes— SQL线程正在运行,正在执行中继日志。
  3. Seconds_Behind_Master: 0— 从库落后于主库的秒数。0表示已完全同步。这个值在持续写入时可能会是一个很小的正数,这是正常的网络和重放延迟。如果这个值持续增长或非常大,说明复制可能跟不上主库的写入速度。
  4. Last_IO_Errno: 0Last_SQL_Errno: 0— 没有错误。

如果Slave_IO_RunningSlave_SQL_RunningNo,或者Last_IO_Error/Last_SQL_Error字段有错误信息,说明复制出了问题。常见的错误包括网络不通、主库用户权限不足、主库的Binlog文件已被清理(Position太旧)等。

5.2 简单功能测试

在从库状态一切正常后,我们可以做一个简单的测试来验证复制是否真的在工作。

  1. 在主库上创建一个测试数据库和表,并插入数据:

    -- 在主库执行 CREATE DATABASE IF NOT EXISTS test_replication; USE test_replication; CREATE TABLE test_table (id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(50)); INSERT INTO test_table (name) VALUES ('data_from_master');
  2. 稍等片刻(通常1秒内),然后在从库上查询:

    -- 在从库执行 USE test_replication; SELECT * FROM test_table;

    如果你能在从库看到data_from_master这条记录,恭喜你,主从复制已经成功运行!

6. 生产环境进阶配置与调优

基础的搭建完成了,但要用于生产环境,我们还需要考虑更多。

6.1 半同步复制(Semisynchronous Replication)

默认的复制是异步的。主库提交事务后,只要将事件写入自己的Binlog,就会立即返回给客户端成功,而不管从库是否收到。如果主库在返回成功给客户端后立刻宕机,且未来得及将Binlog事件发送给任何从库,那么即使有从库被提升为新主,也会丢失这个事务,导致数据不一致。

半同步复制就是为了解决这个问题。它要求主库在提交事务时,必须至少等待一个从库接收并确认(写入Relay Log)了该事务的Binlog事件后,才能返回成功给客户端。这在一定程度上提高了数据的安全性。

配置步骤:

  1. 在主库和从库上安装半同步插件(MySQL 5.7+ 通常已内置):

    -- 在主库执行 INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so'; -- 在从库执行 INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';
  2. 启用插件并设置参数

    -- 在主库执行 SET GLOBAL rpl_semi_sync_master_enabled = ON; SET GLOBAL rpl_semi_sync_master_timeout = 1000; -- 等待从库确认的超时时间(毫秒),超时后会退化为异步 -- 在从库执行 SET GLOBAL rpl_semi_sync_slave_enabled = ON;
  3. 重启从库的I/O线程以应用半同步设置

    -- 在从库执行 STOP SLAVE IO_THREAD; START SLAVE IO_THREAD;
  4. 验证:在主库执行SHOW STATUS LIKE 'Rpl_semi_sync%';,查看Rpl_semi_sync_master_status是否为ON

注意:半同步复制会增加主库事务的响应延迟,因为多了一次网络往返。超时时间rpl_semi_sync_master_timeout需要根据网络状况合理设置。在MySQL 5.7+中,还有了“无损半同步”(Lossless Semisynchronous)的改进,通过调整rpl_semi_sync_master_wait_point参数,可以进一步保证数据不丢失。

6.2 复制过滤规则

你可能不希望所有数据都复制到从库。例如,一些用于缓存的临时表,或者某些日志库。这时可以使用复制过滤。

过滤可以在主库从库进行,但强烈建议只在从库进行过滤。在主库过滤(binlog-do-db,binlog-ignore-db)容易因为USE database;语句的上下文问题导致过滤规则混乱。

在从库配置过滤(推荐): 在从库的my.cnf中配置,或在运行时用CHANGE REPLICATION FILTER命令设置。

# 在my.cnf中 [mysqld] # 只复制db1和db2库 replicate-do-db = db1 replicate-do-db = db2 # 忽略test库和tmp_开头的所有库 replicate-ignore-db = test replicate-wild-ignore-table = tmp_%.%

或者在从库MySQL中动态设置:

STOP SLAVE; CHANGE REPLICATION FILTER REPLICATE_DO_DB = (db1, db2), REPLICATE_IGNORE_DB = (test), REPLICATE_WILD_IGNORE_TABLE = ('tmp_%.%'); START SLAVE;

6.3 延迟复制(Delayed Replication)

有时候,我们希望从库故意延迟一段时间再应用主库的变更。这主要用于防止在主库发生误操作(如DROP DATABASE)时,可以从延迟的从库上找回数据。

-- 在从库上执行 STOP SLAVE; CHANGE MASTER TO MASTER_DELAY = 3600; -- 延迟3600秒(1小时) START SLAVE;

设置后,从库的SQL线程会等待指定的秒数后再执行中继日志中的事件。注意:延迟是针对每个事件计算的,所以从库的Seconds_Behind_Master会稳定在设定值附近。

7. 日常运维、故障排查与切换演练

搭建好只是开始,日常的监控和问题处理才是重头戏。

7.1 监控关键指标

除了手动执行SHOW SLAVE STATUS,在生产环境中,你应该将这些指标集成到监控系统(如Prometheus + Grafana)中。关键指标包括:

  • Slave_IO_Running/Slave_SQL_Running(0/1)
  • Seconds_Behind_Master
  • Last_IO_Errno/Last_SQL_Errno
  • Slave_SQL_Running_State
  • Relay_Log_Space(中继日志占用空间,防止磁盘写满)

7.2 常见故障与处理

1. 主从数据不一致这是最棘手的问题。原因可能是:从库被意外写入、复制过滤规则配置错误、SQL线程错误被跳过等。

  • 检查:使用pt-table-checksum(Percona Toolkit工具)来校验主从数据一致性。
  • 修复:如果差异不大,可以手动修复差异行。如果差异巨大或原因不明,最稳妥的方法是重建从库:在主库做一次新的全量备份,然后在从库停止复制、清空数据、重新导入并配置新的复制起点。

2. 复制中断:SQL线程错误 (Last_SQL_Error)常见错误如1062 (Duplicate entry)主键冲突,或1032 (Can‘t find record)行不存在。

  • 原因:通常是因为从库被直接写入了数据,或者主库上某些操作具有不确定性(在STATEMENT格式下),或者在复制中断期间手动修改了从库数据。
  • 处理
    • 临时跳过:如果确定可以跳过这个错误(比如重复主键,但数据一致),可以执行STOP SLAVE; SET GLOBAL sql_slave_skip_counter = 1; START SLAVE;跳过1个事件。慎用!这可能导致后续更多不一致。
    • GTID模式下的跳过:如果启用了GTID,跳过操作更复杂,需要使用SET GTID_NEXT等命令。
    • 最佳实践:分析错误原因。如果是偶发的重复键,且数据确实一致,可以跳过。否则,应考虑重建从库。

3. 复制延迟 (Seconds_Behind_Master 持续很高)

  • 原因
    • 硬件/网络:从库硬件(尤其是磁盘I/O)比主库差,或网络带宽不足。
    • 单线程瓶颈:传统复制中,SQL线程是单线程的,主库并发写入高时,从库重放跟不上。
    • 大事务:主库执行了一个耗时很长的大事务(如批量更新百万行)。
  • 优化
    • 升级硬件:给从库配置更好的CPU、内存,尤其是使用SSD磁盘。
    • 启用多线程复制 (MTS):MySQL 5.6+ 支持基于库(DATABASE)的并行复制,5.7+ 支持基于逻辑时钟(LOGICAL_CLOCK)的更细粒度并行复制,能极大提升重放速度。
      STOP SLAVE; SET GLOBAL slave_parallel_workers = 4; -- 设置4个并行工作线程 SET GLOBAL slave_parallel_type = 'LOGICAL_CLOCK'; -- MySQL 5.7+ START SLAVE;
    • 避免大事务:优化业务SQL,将大事务拆分为小批次。

7.3 主从切换演练(Failover)

高可用架构不是摆设,必须定期演练。假设主库(192.168.1.100)宕机,我们需要将应用切换到从库(192.168.1.101)。

  1. 确认主库故障:通过监控和人工确认主库无法恢复。
  2. 提升从库为新主库
    -- 在从库(192.168.1.101)上执行 STOP SLAVE; RESET SLAVE ALL; -- 清除所有复制信息,使其成为一个独立的主库
    修改其配置文件,移除read-only=1设置,并重启或动态设置SET GLOBAL read_only = OFF;
  3. 应用层切换:将应用的数据库连接地址从旧主库IP改为新主库IP。这通常需要借助中间件(如MyCat, ProxySQL)或服务发现组件来实现快速、自动的切换。
  4. 其他从库指向新主库:如果还有其他从库,需要将它们重新指向新的主库(192.168.1.101)。
    -- 在其他从库上执行 STOP SLAVE; CHANGE MASTER TO MASTER_HOST='192.168.1.101', MASTER_USER='repl', ...; -- 使用新主库的信息 START SLAVE;
  5. 修复旧主库:旧主库修复后,可以将其作为新主库的从库重新加入集群,形成新的主从关系。

这个过程手动操作非常容易出错且耗时。因此,生产环境强烈建议使用成熟的高可用解决方案,如MHA (Master High Availability)Orchestrator,或云数据库服务商提供的自动故障转移功能。它们能自动化完成故障检测、主从切换、虚拟IP漂移等复杂操作。

搭建和使用MySQL主从复制,就像给数据库系统上了第一道保险。它成本相对较低,却能带来读写分离、负载均衡、数据备份等多重收益。然而,它也不是银弹,异步复制带来的数据延迟、故障切换的复杂性都是需要持续关注和优化的问题。从我个人的经验来看,在项目初期就规划好主从架构,并配套完善的监控和告警,远比出了问题再临时搭建要从容得多。理解其原理,掌握其配置,熟悉其排错,是确保这套机制稳定运行的关键。希望这篇从搭建到使用的详细指南,能帮助你建立起属于自己的、可靠的数据层基础架构。

← 返回列表