主从复制延迟导致读到旧数据需通过强制走主库、SQL注释路由、半同步复制等方案解决;GTID切换需校验gtid_executed并集;MGR多主写冲突会直接回滚;从库crash后应优先用GTID恢复或重建。

主从复制延迟导致读到旧数据怎么办
MySQL 主从复制默认是异步的,SELECT 发到从库时,可能还没收到主库的最新 binlog,结果读到过期数据。这不是 bug,是设计使然。
常见现象:写完立刻查,从库返回空或旧值;监控显示 Seconds_Behind_Master 波动大;业务出现“刚提交就查不到”的投诉。
- 用
SELECT ... FOR UPDATE或SELECT ... LOCK IN SHARE MODE强制走主库(需中间件或应用层识别) - 设置从库
read_only=ON后,对关键读请求加路由标签,比如在 SQL 注释里写/*+ USE_MASTER */,由代理(如 MyCat、Vitess、ShardingSphere)解析并转发 - 启用半同步复制(
rpl_semi_sync_master_enabled=ON),至少等一个从库写入 relay log 才返回成功,但会增加主库响应时间,且超时后自动退化为异步
GTID 模式下主从切换后如何避免事务重复或丢失
启用了 gtid_mode=ON 的集群,故障切换时如果新主库的 Executed_Gtid_Set 不包含旧主库未同步的 GTID,就会丢事务;反之,若从库误重放已执行过的 GTID,则报错 ER_GTID_EXECUTED_BY_OTHER_SERVER。
根本原因在于:GTID 是全局唯一但不自带顺序保证,切换时没校验所有节点的 gtid_executed 并集。
- 切换前用
SELECT @@global.gtid_executed;对比所有节点,确保新主库的集合是其他节点的超集 - 从库启动时加参数
--gtid-mode=ON --enforce-gtid-consistency=ON --log-slave-updates=ON,缺一不可 - 避免手动
SET GLOBAL gtid_purged,除非你清楚 purge 掉的是哪些事务——它会跳过对应 GTID,造成逻辑不一致
多写集群(如 MGR)中写冲突怎么处理
MySQL Group Replication(MGR)支持单主/多主模式,但多主写同一行会触发认证失败(certification failure),不是锁等待,而是直接回滚事务,报错 ERROR 3098 (HY000): The table does not comply with the requirements... 或更常见的 ERROR 1205 (40001): Deadlock found when trying to get lock(实际是认证冲突伪装成死锁)。
这种“一致性”是最终一致 + 冲突裁决,不是强一致。
- 业务层尽量按分片键(shard key)写入,比如用户 ID 哈希后固定写某节点,减少跨节点更新同一记录
- 检查表是否满足 MGR 要求:必须有主键、引擎为
InnoDB、禁用CREATE TABLE ... SELECT类语句 - 开启
group_replication_consistency=AFTER可让读操作等本节点应用完所有已提交事务,但会拖慢查询;默认EVENTUAL下读可能看到“未来事务”未生效前的状态
从库 crash 后重启,为什么复制卡在某个 position/GTID 不动
最常见原因是 relay log 损坏或缺失,或者 relay_log_info_repository=FILE 时 info 文件和实际文件不同步。错误日志里通常有 Could not find first log file name in binary log index file 或 Client requested master to start replication from position > file size。
别急着 CHANGE MASTER TO ... MASTER_LOG_POS 硬跳——跳过的位置可能对应未执行的 DDL,后续表结构就对不上。
- 先确认是否启用了 GTID:
SHOW VARIABLES LIKE 'gtid_mode';,是则优先用RESET SLAVE ALL; SET GLOBAL gtid_purged = 'xxx'; START SLAVE; - 如果是 file:pos 模式,用
SHOW MASTER STATUS在主库查当前位置,再用mysqlbinlog --base64-output=decode-rows -v解析最近几个 binlog,定位出问题的 event 时间点 - 临时修复可设
slave_skip_errors=1062,1032(仅限测试环境),生产环境应重建从库:mysqldump +--set-gtid-purged=ON或使用Percona XtraBackup流式恢复










