一主多从的结构,其实就是读写分离的基本结构了。这里,我再把这张图贴过来,方便你理解。

mysql 读写分离中间件 主从切换 mysql读写分离架构_客户端


读写分离的主要目标就是分摊主库的压力。图 1 中的结构是客户端(client)主动做负载均衡,这种模式下一般会把数据库的连接信息放在客户端的连接层。也就是说,由客户端来选择后端数据库进行查询

还有一种架构是,在 MySQL 和客户端之间有一个中间代理层 proxy,客户端只连接 proxy, 由 proxy 根据请求类型和上下文决定请求的分发路由。

mysql 读写分离中间件 主从切换 mysql读写分离架构_客户端_02


接下来,我们就看一下客户端直连和带 proxy 的读写分离架构,各有哪些特点。

客户端直连方案

因为少了一层 proxy 转发,所以查询性能稍微好一点儿,并且整体架构简单,排查问题更方便。但是这种方案,由于要了解后端部署细节,所以在出现主备切换、库迁移等操作的时候,客户端都会感知到,并且需要调整数据库连接信息。你可能会觉得这样客户端也太麻烦了,信息大量冗余,架构很丑。其实也未必,一般采用这样的架构,一定会伴随一个负责管理后端的组件,比如 Zookeeper,尽量让业务端只专注于业务逻辑开发

带 proxy 的架构

对客户端比较友好。客户端不需要关注后端细节,连接维护、后端信息维护等工作,都是由 proxy 完成的。但这样的话,对后端维护团队的要求会更高。而且,proxy 也需要有高可用架构。因此,带 proxy 架构的整体就相对比较复杂。

理解了这两种方案的优劣,具体选择哪个方案就取决于数据库团队提供的能力了。但目前看,趋势是往带 proxy 的架构方向发展的。

但是,不论使用哪种架构,你都会碰到我们今天要讨论的问题:由于主从可能存在延迟,客户端执行完一个更新事务后马上发起查询,如果查询选择的是从库的话,就有可能读到刚刚的事务更新之前的状态

这种“在从库上会读到系统的一个过期状态”的现象,在这篇文章里,我们暂且称之为“过期读”

前面我们说过了几种可能导致主备延迟的原因,以及对应的优化策略,但是主从延迟还是不能 100% 避免的。

不论哪种结构,客户端都希望查询从库的数据结果,跟查主库的数据结果是一样的。接下来,我们就来讨论怎么处理过期读问题

这里,我先把文章中涉及到的处理过期读的方案汇总在这里,以帮助你更好地理解和掌握全文的知识脉络。这些方案包括:

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

总结

  • 读写分离可以用proxy
  • 读写分离会有过期读的问题