主从延迟
在读写分离架构中,主从延迟会导致‘过期读’,也就是从库已经收到了binlog日志,但是还没有同步完成。这种问的解决方案如下:
1.强制走主库
对于一些实时性要求很高的读请求业务场景,可以强制走主库。比如一些金融类业务。缺点就是压力全在主库,失去了扩展性。
2.sleep等待
人工在产品功能上,做一个等待数秒钟的处理。
3.判断主从无延迟
- 通过show slave statue命令结果中的seconds_behind_master来看主从延迟多少秒
- 通过对比主从的位点,来确认是否有延迟

Master_Log_File和Read_Master_Log_Pos代表主库的的最新位点。
Relay_Master_Log_File和Exec_Master_Log_Pos代表从库执行的最新位点。
主从位点的值相同,代表接收到的日志已全部同步完成,无延迟。
- 通过对比GTID,来确认是否有延迟
- Auto_Position=1,表示这对主备关系使用了GTID协议
- Retrieved_Gtid_Set,是从库收到的所有日志GTID集合
- Executed_Gtid_Set,是从库已执行完成的所有日志GTID集合
通过对比接收到的和执行完成的GTID集合是否相同,判断是否有延迟。
有个问题是,虽然主从存在延迟,但是不代表所有的读请求都是‘过期读’,如果设置读取时强制要求主从无延迟,可能会因为主从之间一直不是完全一致的,而导致读请求无法执行的问题。
半同步复制
对于主库的binlog还没有传递给从库,导致从库不知道已经延迟的问题,可以通过半同步复制解决。
- 事务提交时,主库把binlog发给从库。
- 从库收到binlog后,发回给主库一个ack,表示收到了。
- 主库至少收到一个从库的ack后,才返回给客户端‘事务完成’的确认。
缺点:只对一主一从严格有效,一主多从时,主库只等待第一个ack通知,不能保证所有从库都收到binlog日志。
等待主库位点方案
- trx1 事务更新完成后,马上执行 show master status 得到当前主库执行到的 File 和 Position;
- 选定一个从库执行查询语句;
- 在从库上执行 select master_pos_wait(File, Position, N);
- 如果返回值是 >=0 的正整数,则在这个从库执行查询语句;否则,到主库执行查询语句。
对于 select master_pos_wait(File, Position, N)命令,正常返回一个正整数M,表示从命令执行时刻开始,到同步完file和pos表示的binlog位点,执行了多少条事务。如果同步过程超过N秒,返回-1;如果命令执行时刻已经同步完成了file和pos表示的位点,返回0;如果命令执行等待期间,从库的同步线程发生异常,返回NULL;
等待主库GTID方案
- trx1 事务更新完成后,从返回包直接获取这个事务的 GTID,记为 gtid1;(MySQL5.7之后,写事务后可以把事务对应的GTID返回给客户端)
- 选定一个从库执行查询语句;
- 在从库上执行 select wait_for_executed_gtid_set(gtid1, 1);
- 如果返回值是 0,则在这个从库执行查询语句;否则,到主库执行查询语句。
对于 select wait_for_executed_gtid_set(gtid1, 1)命令,表示等待从库执行的事务中,包含了参数的gtid1,返回0;如果等待超时,则返回1。
没有完美的方案,只有最适合特定业务场景的方案。
