一主多从结构就是基本的读写分离结构,主要目的在于分摊主库的压力。
其中一种架构是将数据库的连接信息放在客户端,由客户端选择后端数据库进行查询。
还有一个架构是MySQL与客户端之间有一个中间代理层proxy,客户端只连proxy由proxy决定分发路径。
第一种架构来说,结构金丹,便于维护,只出现主备切换,库迁移时,只需要在客户端调整数据库连接信息
proxy的架构,对客户端较为友好,因为连接是由proxy决定的,proxy的维护成本高,proxy需要高架构。
不论使用什么架构,都有可能碰到主从延迟的事件,这种从从库上读到系统上过期状态的现象,称之为“过期读”。
我们可以通过一下操作来处理
将查询请求做分类,对于需拿到最新结果的请求,就走主库,对于读到旧数据的请求就走从库。
问题在于,在碰到金融类的项目时,要求所有读都不能为过期读,这就得全走主库,导致主库压力过大。
主库更新后,将从库sleep一下,这个方案假设大多数主备延迟在一秒之内,做一个sleep有很大概率拿到新的数据,但是这个不是很靠谱,因为如果更新的延迟大于一秒就得读旧数据了。
1.判断seconds_behind_master是否为0
2.对比位点
Master_log_file和read_master_log_pos(读到主库的最新位点)
与
Relay_Master_log_file和Exec_Master_log_pos(备库执行的最新位点)
这两组值相同的时候代表同步完成
3.GTID集合
Auto_Position=1 主备使用了GTID协议
Retriered_Gtid_Set(备库收到的GTID集合)和Executed_Gtid_Set(备库已经执行的GTID集合)两个集合相同,代表同步完成。
相比于sleep方案这样的精准度更高,但是还是会出现问题。
有一种情况为主库执行完后写入binlog,返回给客户端的这一刻,还没有将binlog传给备库。
我们可以使用semi_sync来解决
semi_sync做了这样的设计
1.事务提交之后主库binlog给从库
2.从库收到之后,返回一个ack给主库
3.主库收到ack之后才给客户端返回事务已经完成的确认。
一主一备的情况下是成立的,但是一主多从就会出现两种情况
1.查询落到ack从库,相安无事
2.查询的不是ack从库,就有可能出现过期读的情况
其实同步位点的判断还存在着一个问题,比如业务高峰期,主库的GTID更新极快,等到等值判断的时候,是必然不相同的,会造成长时间不响应查询的情况。
看条命令
select master_pos_wait(file , pos[,timeout])
file pos指主库上的文件名和位置
timeout可选,设置为正整数N,表示函数做多等多少秒。
正常结果返回一个正整数M,表示从开始执行到现在应用完file和pos表示的binlog位置,执行了多少事务。
其他结果返回:1.执行过程当中,备库同步线程异常,返回Null
2.超出N,返回-1
3.刚开始执行过这个位置返回0
对于在主库上刚执行完的更新语句,马上执行show master status,得到当前主库的file和position
若返回值为大于等于0的整数,则在这个备库执行查询语言,否则到主库当中执行查询语言。
那么如果超时了,是不是还得去主库呢,其实可以做两个选择:1.超时放弃2.去主库查。
MySQL当中提供了一个类似的命令
select wait_for_executed_gtid_set(gtid_set,1)
这条命令的逻辑是
1.等待1秒,直到这个库执行的事务传给gtid_set,返回0
2.超时返回1
在GTID当中变成
1.trx1事务更新完成后,从返回包当中获取这个事务的GTID记为gtid1
2.选择一个从库进行查询语句
3.在该从库上执行上面那条命令
4.若返回值为0,在这个从库执行查询语句
5.否则就去主库
MYSQL在执行事务后带上GTID需要将参数 session_track_gtids设为OWN_GTID通过API接口msyql_session_track_get_first从返回包查询即可。