主从复制架构:MySQL主从复制的部署流程与常见问题

主从复制这东西,说白了就是让两台MySQL服务器保持数据同步。一台写数据(主库),另一台或者几台只负责读(从库)。为什么这么做?你想想看,如果所有读写都压在一台机器上,哪天它挂了,整个业务就瘫了。我见过不少团队,刚开始觉得单库够用,结果流量一上来,读写全堵在那,直接雪崩。

我的经验是,主从复制是架构中最基础、也最实用的高可用手段。虽然现在有各种新方案,但主从复制依然是运维人的看家本领。今天咱们就围绕三个核心点展开:怎么部署、常见坑怎么踩、状态怎么监控。

核心观点: 主从复制不是银弹,但正确部署后能把单点故障风险降低80%以上。我在项目中吃过亏,才深刻体会到这一步不能偷懒。
MySQL主从复制核心逻辑图 主库 (Master) 写入 · 更新 · 删除 从库 (Slave) 只读 · 查询 · 备份 Binlog Relay Log I/O线程:拉取Binlog到Relay Log SQL线程:重放Relay Log到从库 说明:主库写入 → 生成Binlog → I/O线程拉取 → 写入Relay Log → SQL线程重放 → 从库数据更新 延迟大小取决于网络、SQL线程效率、主库压力

1. 环境准备:确认版本与网络

我个人习惯在正式部署前,先检查两件事。第一,主库和从库的MySQL版本是否一致。我遇到过版本不一样导致数据类型转换出错的情况,折腾了大半天才发现问题。第二,主从之间的网络连通性,尤其注意防火墙和端口。MySQL默认端口是3306,从库需要能直接连接到主库。

小技巧: 用 telnet 主库IP 3306 测试连通性。如果连不上,别急着查MySQL配置,先看安全组和iptables。

2. 配置主库:开启Binlog并设置server-id

主库要能记录所有数据变更,靠的就是Binary Log(简称Binlog)。配置很简单,修改my.cnf,加上以下几行:

[mysqld]
log-bin=mysql-bin
server-id=1
binlog-format=ROW
expire_logs_days=7
max_binlog_size=256M

server-id 这个值必须在集群内全局唯一。我习惯用IP最后一段做编号,比如172.16.1.10就设成10,方便维护,不容易撞车。Binlog格式我推荐用ROW,它按行记录变更,虽然日志会大一些,但数据一致性最好。STATEMENT格式省空间,但遇到不确定函数时容易产生主从不一致。我踩过那个坑,后来再也不敢用STATEMENT了。

3. 创建复制用户

主库上专门创建一个用户,供从库连接拉取Binlog,权限只要REPLICATION SLAVE就够了,别给super或者all privileges,安全第一。

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

密码复杂度建议符合公司安全规范。我曾经犯过用简单密码的错,结果被扫到弱口令,从库IP被人用来发起复制攻击,幸好及时发现没有造成数据泄露。

4. 配置从库:连接主库启动复制

从库的my.cnf相对简单:

[mysqld]
server-id=2
relay-log=mysql-relay-bin
read_only=1
skip-slave-start=ON

read_only=1 是防止有人在从库上误写数据,导致数据不一致。skip-slave-start 我建议开启,避免MySQL重启后自动尝试复制,方便你先确认状态再手动启动。

现在,去从库执行CHANGE MASTER命令:

CHANGE MASTER TO
  MASTER_HOST='主库IP',
  MASTER_USER='repl',
  MASTER_PASSWORD='StrongPassword',
  MASTER_LOG_FILE='mysql-bin.000001',
  MASTER_LOG_POS=154;

START SLAVE;

这里的MASTER_LOG_FILE和MASTER_LOG_POS需要从主库查:在主库执行SHOW MASTER STATUS;,记下File和Position的值。很多新手忘了这一步,导致从库找不到起点,复制失败。

注意: 如果主库已经跑了一段时间,建议先用mysqldump或xtrabackup做一次全量备份,恢复到从库,再启动复制。否则从库可能是空的,SQL线程重放时肯定会出问题。

5. 验证复制状态

在从库上运行:

SHOW SLAVE STATUS\G

你看输出,重点关注两个字段:

  • Slave_IO_Running:是不是 Yes
  • Slave_SQL_Running:是不是 Yes

如果两个都是Yes,恭喜你,主从复制已经跑起来了。我习惯每隔几分钟用脚本扫一遍从库状态,一旦看到No就立刻报警,别等问题发酵。

常见问题与避坑指南

部署完成不代表万事大吉,实际运维中问题多得很。我把自己踩过的雷列出来,你对照着看:

问题现象可能原因解决方法
Slave_IO_Running: No网络不通、用户名密码错误、主库Binlog被清理检查连通性、确认MASTER配置、调整expire_logs_days
Slave_SQL_Running: NoSQL语句冲突(主键重复、表不存在)SHOW SLAVE STATUS看Last_Error,手动修复后STOP SLAVE; SET GLOBAL sql_slave_skip_counter=1; START SLAVE;
复制延迟增长从库性能不足、大事务、网络带宽不够升级从库硬件、拆分大事务、开启并行复制(slave_parallel_workers)
数据不一致主库使用了不确定函数、从库被写数据生产环境用ROW格式、确保从库read_only

分享一个真实案例。有一次我遇到从库SQL线程一直报错,Last_Error显示在主库删了一条记录,但从库对应表里没有这条数据,所以删失败。这种情况其实是因为从库之前被手动插入了相同主键的数据,主库删的时候从库找不到。我当时用SET GLOBAL sql_slave_skip_counter=1跳过去,后续用pt-table-checksum工具完整校验了数据一致性,才彻底恢复。

我的建议: 对于重要业务,每周执行一次pt-table-checksum检查主从一致性。不要等到报警才动手,主动运维才能减少事故。

关于复制延迟的深入理解

你可能会问,为什么从库的Seconds_Behind_Master有时候很大?其实它计算的是SQL线程落后主库的时间。如果主库突然写了几十万行数据,Binlog里一条记录,从库SQL线程要一条条重放,肯定慢。

我在项目中遇到最夸张的一次,延迟达到15分钟。排查后发现是主库在做大表ALTER操作,产生的Binlog太大,从库SQL线程处理不过来。后来我做了一个优化:把大ALTER拆成小批次执行,比如每次只改几千行,同时给从库开启并行复制(slave_parallel_workers设为4),延迟立刻降到了秒级。

还有一个细节:Seconds_Behind_Master在某些场景下不准确。比如主从时钟不同步,这个值就是虚的。所以我更建议用SHOW MASTER STATUS和SHOW SLAVE STATUS中的Binlog坐标对比来算真实延迟,或者用第三方工具。

再提醒一次: 从库不是备胎,它承担着读流量和备份任务。别忘了给从库分配足够的内存和IOPS,否则一有流量高峰,延迟就上来了。

主从切换的简单思路

虽然在第三章节我们主要讲部署,但我还是想提一句切换。如果你需要把从库提升为主库,流程大致是:停止从库复制 → 确认从库追上主库数据 → 在从库上STOP SLAVE; RESET MASTER; → 更改应用连接指向新主库。但我建议在切换前先做一次从库数据校验,确保没有丢事务。这步我吃过亏,切换完发现少了几天数据,最后只能从备份恢复,血泪教训。

好,关于主从复制的部署流程和常见问题,今天就聊到这儿。记住,复制不是一锤子买卖,上线后要持续监控、定期巡检,才能让你的数据库架构真正扛得住压力。