• 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

  • 相关阅读:
    class类文件具有错误的版本52.0,应为50.0
    git learn.
    git diff 命令用法
    vlan
    bridge
    Packet flow in l2(receive and transmit)
    /proc/uptime详解
    linux 内核数据结构之红黑树.
    linux 内核数据结构之 avl树.
    python学习.
  • 原文地址:https://www.cnblogs.com/linyihai/p/16120278.html
Copyright © 2020-2023  润新知