强制走主库方案;
sleep方案;
判断主备无延迟方案;
配合semi-sync方案;
等主库位点方案;
等GTID方案。

1 强制走主库方案

最常用

2 sleep方案

类似于执行一条select sleep(1)命令。这个方案的假设是, 大多数情况下主备延迟在1秒之内, 做一个sleep可以有很大概率拿到最新的数据。
问题
1. 如果这个查询请求本来0.5秒就可以在从库上拿到正确结果, 也会等1秒;
2. 如果延迟超过1秒, 还是会出现过期读。

3 判断主备无延迟方案

3.1 从库执行查询请求前, 先判断seconds_behind_master是否已经等于0。 如果还不等于0 , 那就必须等到这个参数变为0才能执行查询请求。
缺点:秒级不精确

3.2 第二种方法, 对比位点确保主备无延迟:
Master_Log_File和Read_Master_Log_Pos, 表示的是读到的主库的最新位点
Relay_Master_Log_File和Exec_Master_Log_Pos, 表示的是备库执行的最新位点。
如果Master_Log_File和Relay_Master_Log_File、 Read_Master_Log_Pos和Exec_Master_Log_Pos这两组值完全相同, 就表示接收到的日志已经同步完成

3.3 对比GTID集合确保主备无延迟:
Auto_Position=1 , 表示这对主备关系使用了GTID协议。
Retrieved_Gtid_Set, 是备库收到的所有日志的GTID集合;
Executed_Gtid_Set, 是备库所有已经执行完成的GTID集合。
如果这两个集合相同, 也表示备库接收到的日志都已经同步完成

2和3的缺点

同步位点的方案还有另外一个潜在的问题, 即: 如果在业务更新的高峰期, 主库的位点或者GTID集合更新很快, 那么上面的两个位点等值判断就会一直不成立, 很可能出现从库上
迟迟无法响应查询请求的情况。

4 配合semi-sync


semi-sync+位点判断的方案

缺点:
1. 一主多从的时候, 在某些从库执行查询请求会存在过期读的现象;
2. 在持续延迟的情况下, 可能出现过度等待的问题

5 等主库位点方案

select master_pos_wait(file, pos[, timeout]);
1. 它是在从库执行的;
2. 参数file和pos指的是主库上的文件名和位置;
3. timeout可选, 设置为正整数N表示这个函数最多等待N秒。

流程:
1. trx1事务更新完成后, 马上执行show master status得到当前主库执行到的File和Position;
2. 选定一个从库执行查询语句;
3. 在从库上执行select master_pos_wait(File, Position, 1);
4. 如果返回值是>=0的正整数, 则在这个从库执行查询语句;
5. 否则, 到主库执行查询语句

缺点:基本不可行,记不住储存的位点

6 等GTID方案

与方案五 差不多。select wait_for_executed_gtid_set(gtid_set, 1);

7 总结:

在实际应用中, 这几个方案是可以混合使用的。
比如, 先在客户端对请求做分类, 区分哪些请求可以接受过期读, 而哪些请求完全不能接受过期
读; 然后, 对于不能接受过期读的语句, 再使用等GTID或等位点的方案