主从复制延迟导致读到旧数据需通过强制走主库、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(实际是认证冲突伪装成死锁)。