引入
mysql生产环境通常都是集群部署,一般都是一主(读写)多从(只读)
当客户端发起查询的时候,服务端此时提交事务,主从库同步需要一定时间,这时候就产生主从延迟,客户端会读取到旧数据
读写分离架构
1.客户端选库
读写分离交由客户端来处理,由客户端主动选择操作那个库
2.代理模式
客户端连接代理,由代理选择操作哪个库
2中方式各有优势
客户端选库:
架构简单,性能较好,但和客户端没有解耦,每次操作客户端都会感知到
代理选库:
引入中间件,虽然解耦了,但是性能会有影响,引入组件架构变复杂需要维护
解决方案
-
强制主库
最简单的方案,对于实时要求性较高的数据可以走主库,而其他请求走从库。这回导致一个问题就是当所有请求都要求强一致性的话主库就完了。 -
Sleep方案
每次查询先延迟几秒。比如当发微博的时候,点击发送先保存本地再请求数据库,之后查询的话直接显示本地缓存,相当于延迟了几秒,失效后再真正查库。 -
判断主备无延迟方案
直接根据从库的具体延迟数据来进行延迟查询,使用show slave status
可以查询具体延迟时间seconds_behind_master
,来决定到底应该延迟多久。该单位为秒。
如果你觉得精确度不高的话,还可以通过对比位点和GTID集合是否形同来判断是否同步完成
位点:
read_master_log_pos
该值为读到的master的binlog当前位置
exec_master_log_pos
该值为当前从库执行的最新位置
当这两个值相同的话说明主库无延迟
GTID:
restrieved_gtid_set
和executed_gtid_set
相同说明同步完成
因为该方案都是基于从库已经读到的日志文件来作为比较基准。当主库有部分数据还未发送到从库的时候此时还是出现了主库延迟。 -
配合semi-sync
半同步复制,每当主库开启一个事务后,提交前都会将bin_log发送给从库,只有从库返回ack后才会将事务的成功返回客户端。该方案配合对比位点的方式会确保强一致性,但是只针对一主一从。
当面对多从的时,主库发送bin_log同步请求,只要有一个从库同步完成回复ack就会将事务成功返回给客户端。此时查询会有一定几率落到为同步的从库。
当然还有一个问题,当业务高峰期,主库和从库会一直进行数据同步,此时导致延迟查询得不到返回结果。 -
等主库位点方案
对比位点和gtid当业务高峰会导致永远不相同。此时可以通过
select master_pos_wait(file, pos, [timeout])
该查询在从库执行返回截止到入参执行了多少事务,如果超时返回-1,发生异常返回null。
具体查询逻辑:
1.当主库更新事务后,立刻执行show slave status来查询当前binlog的位置,f和p
2.在要查询的从库执行select master pos wait入参为步骤1查询到的f和p
3.根据步骤2,判断该从库是否已经执行完主库的刚刚更新的最新位置,是的话直接查询返回结果,否则查询主库最新数据