Mysql有什么办法解决主备延迟的引起的过期读问题?
Mysql有什么办法解决主备延迟的引起的过期读问题?
一主多从的架构,主写入和少量的读,从库承担大量的读。读从库有不可避免的延迟,有些业务是不允许过期读。
强制走主库方案
比如金融类的业务就必须查询主库
sleep 方案
某些特殊场景下可能有用,比如淘宝商家发布商品后,只用将发布的内容展示在页面上,而后台查询时延迟1s在查询。
判断无延迟方案
从库执行show slave status
可以看到主库和备库同步位点,gtid_set, auto_position参数
- 根据
seconds_behind_master
参数的值,当其值为0才能查询。 - 对比位点。方法是根据show slave status 查询出的 Master_Log_File和Read_Master_Log_Pos 表示是读到的主库最新位点;Relay_Master_Log_File和Exec_Master_Log_Pos 表示的是备库执行的最新位点。于是根据主库最新位点和备库最新位点最新位点是否一致来判断同步是否完成
- 对比GID,Auto_Position, 表示主备使用GTID协议同步了, 如果Retrieve_Gtid_Set和Executed_Gtid_Set相同,表示主备同步可以查询
判断无延迟的三种办法,本质上还是备库根据已经同步到备库binlog来判断,如果事务提交了,主库回应客户端事务提交了,而binlog在主库还没同步到备库,客户端马上来备库查询,使用判断无延迟方案,此时是没有延迟的,读备库就是过期读
配合semi-sync 方案
因此,如果主库在执行完事务,然后确保binlog同步给了从库,再响应客户端。
一主一备 + semi-sync + 位点判断 的方案有点不足
- 当然是一主多从,semi-sync是一个库ack,就给客户端返回确认。这就导致某些库会过期读
- 主库有频繁的事务提交时,备库的同步位点将一直落后从库, 甚至出现过度等待情况,即主库执行了tr1,tr2,tr3,客户端此时收到tr1执行成功就去从库查询,此时从库有tr1的binlog,但此时因为还有tr2,tr3需要同步,不能马上查询
等主库位点方案
select master_pos_wait(file, pos[, timeout])
这个命令时从库用来获取主库基于(file, pos)位点后是否有新的提交,返回值有:
- NULL,表示备库同步线程发生异常
- 等待超过N秒,返回-1
- 返回0,表示已经执行过了
当收到客户端查询时,从库执行show master status
获取(File, Position),然后
当select master_pos_wait(File, Position, 1) >= 0 表示从库此时已经同步执行完主库的事务了,可以进行查询。
GTID
select wait_for_executed_gtid_set(gtid_set, 1)
在超时时间内,如果执行事务包括gtid_set, 那么返回0,超时返回1。
MySQL 5.7.6之后,允许将提交事务的GTID返回客户端。
使用GTID避免过期读:
- trx1 执行完后将gtid给客户端
- 客户端通过gtid选择一个从库查询
- 从库执行
select wait_for_executed_gtid_set(gtid, 1);
- 根据返回值为0就查询,否则回到主库查询。
命令
- show master status 查看主库当前binlog执行情况
- show slave status 显示当前备库执行同步过来的binlog情况