面试官问:在读多写少的情况下,如何优化 MySQL 的数据查询方案
面试官问:假设你负责的某业务在双十一期间要搞运营活动,公司投入了大量的营销费用进行推广,此举会带来巨大的流量,如果你作为架构师或者技术负责人,要如何设计方案来优化 MySQL,从而支持这种突发流量的读多写少的场景?

binlog 的写入:MySQL 主库在收到客户端提交事务的请求后,会先把相关操作写入 Binary Log,然后再提交事务,更新存储引擎中的数据,事务提交完成后,返回给客户端操作成功的响应;
binlog 的同步:MySQL 从库会创建一个专门的 I/O 线程,它会连接主库的 binlog dump 线程,从主库接收 binlog 日志文件,然后把 binlog 信息写入本地的 relay log 中继日志文件中,最后返回复制成功的响应给主库;
binlog 的回放:同时,从库会创建一个 SQL 线程,它会读取 relay log 中继日志,然后回放 binlog 从而更新存储引擎中的数据,最终实现主从数据的复制和一致性。

异步方式:MySQL 提交事务的线程完全不关心 binlog 是否已经同步到从库,事务执行完成就会返回客户端响应结果,这种模式如果主库宕机,数据存在丢失的风险;
同步方式:MySQL 提交事务的线程会等待所有从库 binlog 同步成功的响应,这种情况不存在丢数据的情况;
半同步方式:MySQL 5.7 版本之后增加的功能,MySQL 提交事务的线程不会等待所有从库 binlog 同步成功的响应,只要有一部分从库同步成功,它就会返回客户端响应结果,同样的,这种方式也不存在丢数据的风险,但性能又比同步方式高。
数据放到缓存中:在数据写入主库的同时,也写到缓存(例如 Redis)中,而读取数据时,优先从缓存中读取。不过这种方案存在缓存和数据库一致性的问题,不过这个属于另外一个范畴了,也存在解决方案,这里就不细说了。
读主库:通常情况下,我们是禁止读主库的,因为主库存在写请求,会锁行,如果查询的数据量很大且频繁时,会影响读请求的执行,最终对主库造成较大的压力。所以这个方案的执行要谨慎考虑。
自己改造代码,判断 SQL 语句是读还是写,从而将这条语句发送到对应的数据源(主库或者从库)中进行处理
部署代理中间件,例如 MyCat,由中间件来处理读写分离,此种方式对对开发者透明,缺点是会增加 SQL 请求的链路长度,增加网络调用的开销
使用内嵌到服务中的分库分表组件,例如 Sharding JDBC,该组件会代理所有的数据库请求,自动将请求路由到对应数据库实例上。
拓展阅读
关于我
微信公众号:面试官问,原创高质量面试题,始于面试题,但不止于面试题。
