MySQL 如何解决主从分离带来的过期读问题

读写分离有哪些坑?

读写分离存在的问题,主要是从库不可避免存在同步延迟,导致客户端在从库读取到旧数据。

读写分离架构

读写分离主要目的时分摊主库的压力。

上面的结构是client主动选择后端数据库。

还有一种结构是带Proxy的读写分离架构

客户端直连和带proxy读写分离架构的优缺点

  1. 客户端直连结构简单,相比proxy少了一层转发,性能好一点。缺点是clent和后端架构耦合严重,比如主备切换,库迁移都需要调整客户端。

  2. 带proxy的架构,相当于是hold住了后端的所有细节。对技术要求高,比如要求proxy高可用

过期读的问题

由于主从延迟的问题,从库的读取到的结果可能是旧的。

有几种方案可以解决:

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

强制走主库

对请求做分类,将需要马上拿到最新结果的查询放到主库查询,其他请求放到从库执行。

Sleep方案

从库查询前执行前执行一次Sleep(1)。感觉不太靠谱

判断主备无延迟方案

  1. show slave status 查看seconds_behind_master ,判断seconds_bebind_master是否为0,为0就读从库。

  2. 对比位点

主库:Master_Log_File,Read_Master_Log_Pos
从库:Relay_Master_Log_File, Exec_Master_Log_Pos

只要主库和从库上面两组值相同,表示接受到的日志已经完全同步完成。

  1. 对比GTID集合

  2. Auto_Position=1 ,表示这对主备关系使用了 GTID 协议。

  3. Retrieved_Gtid_Set,是备库收到的所有日志的 GTID 集合;

  4. Executed_Gtid_Set,是备库所有已经执行完成的 GTID 集合。

如果Retrieved_Gtid_Set = Executed_Gtid_Set 表示备库接受到的日志都已经同步完成。

GTID 集合表示的是从库上已经收到的事务日志,对于主库已经执行完成,给客户端确认,但是还没通过binlog发给从库执行,这部分内容如果客户端到从库读取会发现还没同步到从库的

配合semi-sync

半同步确认指的是主库提交binlog后,要等至少一个从库确认收到了确认才会给客户端确认。

开启semi-sync 配置前面的对比位点或对比gtid集合,就能保证从库不会出现过期读。但是只适合一主一从的架构,如果有多个从库,由于半同步是只要一个从库有确认,就给客户端确认,那么其他没有得到确认的从库还是会出现过期读。

到这里,我们小结一下,semi-sync 配合判断主备无延迟的方案,存在两个问题:

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

等主库位点方案

select master_pos_wait(file, pos[, timeout]);

上面这条命令是在从库执行,表示在timeout时间内,等主库binlog文件file执行到pos位置返回执行了多少事务,如果是>=0 表示pos已经被执行了,超时则返回-1.

利用上面这个命令,我们有了等主库位点方案

  1. 执行完事务后,马上执行show master status, 得到主库执行到的File和Position
  2. 在从库执行select master_pos_wait(file, position, 1);
  3. 如果上面的语句返回时大于等于0,就在这个从库执行查询语句
  4. 否则到主库查询。

这个方案有个缺点就是,如果从库等主库位点都超时了,主库要做限流策略

GTID方案

MySQL 5.7.6 版本开始,允许在执行完更新类事务后,把这个事务的 GTID 返回给客户端,这样等 GTID 的方案就可以减少一次查询。

客户端在从库执行

 select wait_for_executed_gtid_set(gtid_set, 1);

等待,直到这个库执行的事务中包含传入的 gtid_set,返回 0;超时返回 1。

问题是,怎么能够让 MySQL 在执行事务后,返回包中带上 GTID 呢?你只需要将参数 session_track_gtids 设置为 OWN_GTID,然后通过 API 接口 mysql_session_track_get_first 从返回包解析出 GTID 的值即可。

高级用法: https://dev.mysql.com/doc/refman/5.7/en/c-api-functions.html

posted @ 2022-04-08 23:06  yihailin  阅读(264)  评论(0编辑  收藏  举报