数据库读写分离这个坑,你应该踩过吧?

Hello,你们好!我是楼下小黑哥,我又来了~数据库

今天分享一下刚入职公司第一次发布项目遇到的一个问题,一个数据库读写分离的坑。缓存

前言

事情是这样的,刚入职的时候接到了这样的一个业务需求:架构

每一个支付通道支付失败的时候都会返回特定的错误码,业务内部须要将通道特定的错误码转义成内部的错误码,这样对外就能够统一返回咱们本身的错误码。并发

这个需求其实不难,当时设计的系统架构以下:异步

新增规则的流程简单分为三步:ide

  1. 业务人员经过管理后台新增映射规则
  2. 数据库新增、修改这条映射规则
  3. 删除缓存

这里之因此增长缓存,是由于这个场景每次支付都须要使用,使用缓存能够避免每次都去数据库读取,增长读取速度。性能

后续支付请求业务流程以下:学习

数据库读写分离-用户操做

当缓存内映射规则不存在的时候,将会查询数据库,而后加载到缓存中。若是缓存内映射规则已存在,将会直接使用缓存内映射规则。测试

这个业务流程其实比较简单,当时在测试环境测试也没问题,后续发布线上环境的却碰到奇怪的问题。优化

新增规则以后,一段时间内,映射规则并无生效。查看日志发现,查询数据库的时候,没有数据。

这就很奇怪了,日志显示新增是成功,可是查询却没有数据。可是过了一段时间,再次查询却又有了数据。

走查了下代码,发现并无什么问题,次日上班的时候请教了一下同事,才知道问题的缘由:

原来线上的数据库采用主从架构,数据读写分离,数据查询走的是从库。数据写入都是直接操做主库,后续再同步到从库。

因为数据库同步存在延时,这就致使数据同步的这段时间,主从数据将会不一致,从库没法查询到最新的数据。

若是你以前的数据库系统架构是单库或者主备结构,当你第一次转到数据读写分离架构,这个坑大几率也会踩到。

数据库系统架构发展

下面咱们首先了解一下数据库系统架构,最后再来看下如何解决主从同步延时的致使数据不一致。

主备架构

业务发展的前期,数据访问量小,这时咱们能够直接采用单库的架构。

不过咱们通常不使用的上面的架构,由于存在单点的问题。若数据库出现故障,这段期间业务将会不可用。咱们除了等待重启,其余没什么解决办法。

因此咱们会增长一个备库,实时同步主库的数据。

主备架构

一旦「主库」出了故障,经过人工的方式,手动的将「主机」踢下线,将「备机」改成「主机」来继续提供服务。

这种架构,部署维护简单,业务开发也无需任何改造。

不过缺点也很明显,备库只有在主库有问题的时候才会被启用,存在必定的资源浪费的状况。

主从架构

随着业务发展,请求量不断变大,数据量也不断变大,业务变得更加复杂,很快数据将会到达瓶颈。

因为大多数业务都是读多写少,因此数据库读的最容易成为系统瓶颈。

这时候咱们能够提升读的性能,这时咱们的能够采用的方案,增长从实例,主从同步,数据读写分离。

能够看到这个架构与主备没什么区别,主要区别在于主从架构下,从库与主库同样,时刻须要干活,主库提供写服务,从库只提供读服务。

若是后续读的压力仍是太大,咱们还能够增长从库的数量,水平扩充读的能力。

虽然主从架构帮咱们解决读的瓶颈,可是因为主从之间须要数据同步,这自然就存在必定延时。

在这延时窗口期内,从库的读只能读到一个旧数据,这也是上面案例问题的真正的缘由。

接下来咱们来看下有什么办法能够优化这种状况。

主从延时解决办法

忍受大法

第一种解决办法,很简单,无他,无论他,没有读到也没事。这时业务不须要任何改造,你好,我好,她也好~

若是业务对于数据一致性要求不高,咱们就能够采用这种方案。

数据同步写方案

主从数据同步方案,通常都是采用的异步方式同步给备库。

咱们能够将其修改成同步方案,主从同步完成,主库上的写才能返回。

  1. 业务系统发起写操做,数据写主库
  2. 写请求须要等待主从同步完成才能返回
  3. 数据读从库,主从同步完成就能读到最新数据

这种方案,咱们只须要修改数据库之间同步配置便可,业务层无需修改,相对简单。

不过,因为主库写须要等待主从完成,写请求的时延将会增长,吞吐量将会下降。

这一点对于如今在线业务,可能没法接受。

选择性强制读主

对于须要强一致的场景,咱们能够将其的读请求都操做主库,这样读写都在主库,就没有不一致的状况。

这种方案业务层须要改造一下,将其强制性读主,相对改造难度较低。

不过这种方案相对于浪费了另外一个数据库,增长主库的压力。

中间件选择路由法

这种方案须要使用一个中间件,全部数据库操做都先发到中间件,由中间件再分发到相应的数据库。

这时流程以下:

  1. 写请求,中间件将会发到主库,同时记录一下此时写请求的 key(操做表加主键等
  2. 读请求,若是此时 key 存在,将会路由到主库
  3. 必定时间后(经验值),中间件认为主从同步完成,删除这个 key,后续读将会读从库

这种方案,能够保持数据读写的一致。

可是系统架构增长了一个中间件,总体复杂度变高,业务开发也变得复杂,学习成本也比较高。

缓存路由大法

这种方案与中间件的方案流程比较相似,不过改形成本相对较低,不须要增长任何中间件。

这时流程以下:

  1. 写请求发往主库,同时缓存记录操做的 key,缓存的失效时间设置为主从的延时
  2. 读请求首先判断缓存是否存在
    • 若存在,表明刚发生过写操做,读请求操做主库
    • 若不存在,表明近期没发生写操做,读请求操做从库

这种方案相对中间件的方案成本较低,可是呢咱们此时又引入一个缓存组件,全部读写之间就又多了一步缓存操做。

总结

咱们引入主从架构,数据读写分离,目的是为了解决业务快速发展,请求量变大,并发量变大,从而引起的数据库的读瓶颈。

不过当引入新一个架构解决问题时,势必会带来另一个问题,数据库读写分离以后,主从延迟从而致使数据不一致的状况。,

为了解决主从延迟,数据不一致的状况,咱们能够采用如下这几种方案:

  1. 忍受大法
  2. 数据库同步写方案
  3. 选择性强制读主
  4. 中间件选择路由法
  5. 缓存路由大法

上面的方案都有各自的优势,固然也有相应的缺点,咱们须要根据本身的业务状况,选择相应的解决方案。

好了,今天的文章就到此。

我是楼下小黑哥,下周见~

参考连接

  1. 数据库主从不一致,怎么解?

欢迎关注个人公众号:小黑十一点半,得到平常干货推送。若是您对个人专题内容感兴趣,也能够关注个人博客:studyidea.cn

相关文章
相关标签/搜索