📌今日关键词:MySQL、主从复制、复制模式、异步复制、半同步复制、GTID、组复制、binlog、读写分离
大家好,我是数据库小学妹 👋
之前写过主从复制基础搭建的笔记。讲了原理和读写分离。但有个关键问题当时没展开:复制模式怎么选?
MySQL支持好几种复制模式,每种对数据安全的保证完全不同。选错了轻则丢数据,重则影响业务。
我第一次搭主从,直接用了默认模式。根本没想过这回事。直到出了问题才知道,复制模式不是"能用就行"的配置。
今天把几种模式整理出来,配上配置和踩坑经历。
先看全局:四种模式一张表
MySQL目前有四种复制模式,各有优劣:
| 模式 | 性能 | 数据安全 | 复杂度 | 适用场景 |
|---|---|---|---|---|
| 异步复制 | 最高 | 最低 | 最低 | 读写分离、允许少量丢数据 |
| 半同步复制 | 略低 | 较高 | 中等 | 大多数业务场景 |
| GTID复制 | 同上 | 同上 | 中等 | 需要自动切换的场景 |
| 组复制MGR | 最低 | 最高 | 最高 | 金融、支付等强一致场景 |
没有"最好"的模式,只有最适合你业务的模式。
异步复制:默认模式就够了吗
MySQL默认就是异步复制。主库写完binlog就返回,不等从库确认。
# 默认配置,不需要额外设置
# my.cnf 中只要配好 server-id 和 log-bin 就行
log-bin = mysql-bin
server-id = 1
大部分读写分离场景用异步就够了。性能最好,配置最简单。
但要注意风险:主库宕机时,从库可能没收到最新binlog。已提交但未同步的事务就丢了。
我第一次搭主从就是用的异步模式。当时觉得"主库哪有那么容易挂"。结果主库磁盘故障,切到从库后发现丢了十几条订单。从那以后才认真研究其他模式。
半同步复制:数据安全的第一步
半同步的意思是:主库等从库确认收到binlog后,才返回客户端。
配置方法
-- 主库安装插件
INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';
SET GLOBAL rpl_semi_sync_master_enabled = 1;
SET GLOBAL rpl_semi_sync_master_timeout = 1000;
-- 从库安装插件
INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';
SET GLOBAL rpl_semi_sync_slave_enabled = 1;
STOP SLAVE IO_THREAD;
START SLAVE IO_THREAD;
AFTER_SYNC 和 AFTER_COMMIT
5.7默认是AFTER_SYNC模式,比5.6的AFTER_COMMIT更安全。
AFTER_COMMIT下,主库先提交再等从库确认。这期间其他事务能看到未确认的数据。主库宕机后切换,这部分数据可能丢失。
AFTER_SYNC下,主库写完binlog后等从库确认,再提交。保证了主从一致性。
超时参数怎么调
rpl_semi_sync_master_timeout控制等多久没收到确认就降级为异步。默认1000毫秒。
这个值要根据业务容忍度来调。设太小容易误降级,设太大主库响应变慢。我一般先设1000,观察监控再调。
半同步降级监控
-- 主库查看半同步状态
SHOW STATUS LIKE 'Rpl_semi_sync_master_status';
这个变量是关键。 如果变成OFF,说明已经降级为异步了。从库断连、从库重启都可能触发降级。
降级后复制继续工作,但数据安全性打了折扣。配置时很多人只看复制是否正常,但忽略了这个状态变量。
GTID复制:主从切换的利器
GTID即全局事务ID,格式是server_uuid:transaction_id。
开启后最大的好处:主从切换时从库自动找到复制位置。不用手动管binlog文件和位置。
# my.cnf 配置
gtid_mode = ON
enforce_gtid_consistency = ON
GTID的限制
注意:开启enforce_gtid_consistency后,CREATE TABLE...SELECT会被禁止。因为它不是原子操作。
-- 报错写法
CREATE TABLE new_table SELECT * FROM old_table;
-- 正确写法
CREATE TABLE new_table LIKE old_table;
INSERT INTO new_table SELECT * FROM old_table;
LOAD DATA INFILE在GTID模式下也有特殊要求。升级前务必在测试环境验证所有SQL。
GTID升级前要做的事
不是所有SQL都兼容GTID。建议先在测试环境开启GTID,跑一遍现有的SQL和脚本。确认没报错再上生产。
我见过直接在生产开GTID的。定时脚本里不兼容的SQL全部报错。
组复制MGR:强一致场景的选择
组复制基于Paxos协议,最少三个节点。支持自动故障检测和主库选举。
数据一致性最高,但性能开销也最大。运维复杂度比前几种都高。
金融、支付场景对一致性要求极高的可以考虑。常规业务半同步就够了。
binlog格式:和复制模式配合
binlog格式和复制模式是两回事,但经常一起讨论。生产推荐ROW格式。
-- 查看当前格式
SHOW VARIABLES LIKE 'binlog_format';
-- 动态修改(建议写配置文件)
SET GLOBAL binlog_format = 'ROW';
STATEMENT记录SQL,binlog小,但NOW()、UUID()等函数有问题。ROW记录行变化,数据一致性最好。5.7.7之后ROW已经是默认值了。配合并行复制效果也好。
从库保护:别忘了这一步
配好复制模式还不够,从库默认是可写的。误写从库会导致主从数据不一致。
# my.cnf 配置
super_read_only = ON
read_only = ON
super_read_only比read_only更严格。它连超级用户的写操作也禁止了。建议两个都开。
-- 验证配置
SHOW VARIABLES LIKE 'read_only';
SHOW VARIABLES LIKE 'super_read_only';
-- 都应该是ON
注意:super用户仍然可以通过SET改回来。所以运维规范也很重要。
我踩过的三个坑
案例一:半同步降级没发现
主库配了半同步,timeout设1秒。跑了半年多一直正常。
有次从库IO线程重启后,主库半同步悄悄降级了。监控显示IO、SQL线程都正常,Seconds_Behind_Master也是0。
但Rpl_semi_sync_master_status已经变成OFF了。降级为异步复制,数据安全性大打折扣。
直到主库故障切换才发现丢了十几条关键数据。
解决:重启从库IO线程,让主库重新握手。根本方案是加上半同步状态监控告警。
案例二:开GTID导致现有SQL报错
在从库开启GTID,重启复制后SQL线程直接报错。
原因是数据库里有个定时脚本用了CREATE TABLE...SELECT。GTID模式下这个语法被禁止了。
幸好凌晨低峰期操作,及时改写脚本才没影响业务。
教训:开GTID前,先在测试环境验证所有SQL。
案例三:新搭从库忘配只读
有一次新搭从库漏了super_read_only配置。开发同事误连从库,跑了insert测试数据。
主从数据不一致,排查了好久才定位到是被从库误写了。用pt-table-checksum校验修复后才恢复。
现在我把检查只读写进了标准搭建流程。
避坑清单
- 主从配置要一致:binlog格式、sql_mode、字符集,主从必须一模一样
- 半同步状态要监控:Rpl_semi_sync_master_status变成OFF就是降级了
- GTID模式要测试:开启前在测试环境跑一遍所有SQL
- CREATE TABLE...SELECT要改写:GTID模式下这个语法被禁止
- 从库必须开只读:super_read_only和read_only都开,防止误写
- 超时参数要调:rpl_semi_sync_master_timeout根据业务容忍度设
- 数据要校验:定期用pt-table-checksum做数据校验
- 监控要全面:半同步状态、延迟、IO和SQL线程,一个都不能少
回到开头的问题:复制模式到底怎么选?
追求性能用异步,追求安全用半同步。金融场景上组复制。需要自动切换就开GTID。
模式选错轻则丢数据,重则影响业务。花半天搞懂这几种模式,比出了问题再救火值太多了。
我是数据库小学妹,咱们下篇见 👋