Hello,大家好!我是楼下小黑哥,我又来了~
明天分享一下刚入职公司第一次公布我的项目遇到的一个问题,一个数据库读写拆散的坑。
前言
事件是这样的,刚入职的时候接到了这样的一个业务需要:
每个领取通道领取失败的时候都会返回特定的错误码,业务外部须要将通道特定的错误码本义成外部的错误码,这样对外就能够对立返回咱们本人的错误码。
这个需要其实不难,过后设计的零碎架构如下:
新增规定的流程简略分为三步:
- 业务人员通过治理后盾新增映射规定
- 数据库新增、批改这条映射规定
- 删除缓存
这里之所以减少缓存,是因为这个场景每次领取都须要应用,应用缓存能够防止每次都去数据库读取,减少读取速度。
后续领取申请业务流程如下:
当缓存内映射规定不存在的时候,将会查询数据库,而后加载到缓存中。如果缓存内映射规定已存在,将会间接应用缓存内映射规定。
这个业务流程其实比较简单,过后在测试环境测试也没问题,后续公布线上环境的却碰到奇怪的问题。
新增规定之后,一段时间内,映射规定并没有失效。查看日志发现,查询数据库的时候,没有数据。
这就很奇怪了,日志显示新增是胜利,然而查问却没有数据。然而过了一段时间,再次查问却又有了数据。
走查了下代码,发现并没有什么问题,第二天下班的时候求教了一下共事,才晓得问题的起因:
原来线上的数据库采纳主从架构,数据读写拆散,数据查问走的是从库。数据写入都是间接操作主库,后续再同步到从库。
因为数据库同步存在延时,这就导致数据同步的这段时间,主从数据将会不统一,从库无奈查问到最新的数据。
如果你之前的数据库系统架构是单库或者主备构造,当你第一次转到数据读写拆散架构,这个坑大概率也会踩到。
数据库系统架构倒退
上面咱们首先理解一下数据库系统架构,最初再来看下如何解决主从同步延时的导致数据不统一。
主备架构
业务倒退的后期,数据访问量小,这时咱们能够间接采纳单库的架构。
不过咱们个别不应用的下面的架构,因为存在单点的问题。若数据库呈现故障,这段期间业务将会不可用。咱们除了期待重启,其余没什么解决办法。
所以咱们会减少一个备库,实时同步主库的数据。
一旦「主库」出了故障,通过人工的形式,手动的将「主机」踢下线,将「备机」改为「主机」来持续提供服务。
这种架构,部署保护简略,业务开发也无需任何革新。
不过毛病也很显著,备库只有在主库有问题的时候才会被启用,存在肯定的资源节约的状况。
主从架构
随着业务倒退,申请量一直变大,数据量也一直变大,业务变得更加简单,很快数据将会达到瓶颈。
因为大多数业务都是读多写少,所以数据库读的最容易成为零碎瓶颈。
这时候咱们能够进步读的性能,这时咱们的能够采纳的计划,减少从实例,主从同步,数据读写拆散。
能够看到这个架构与主备没什么区别,次要区别在于主从架构下,从库与主库一样,时刻须要干活,主库提供写服务,从库只提供读服务。
如果后续读的压力还是太大,咱们还能够减少从库的数量,程度裁减读的能力。
尽管主从架构帮咱们解决读的瓶颈,然而因为主从之间须要数据同步,这人造就存在肯定延时。
在这延时窗口期内,从库的读只能读到一个旧数据,这也是下面案例问题的真正的起因。
接下来咱们来看下有什么方法能够优化这种状况。
主从延时解决办法
忍耐大法
第一种解决办法,很简略,无他,不论他,没有读到也没事。这时业务不须要任何革新,你好,我好,她也好~
如果业务对于数据一致性要求不高,咱们就能够采纳这种计划。
数据同步写计划
主从数据同步计划,个别都是采纳的异步形式同步给备库。
咱们能够将其批改为同步计划,主从同步实现,主库上的写能力返回。
- 业务零碎发动写操作,数据写主库
- 写申请须要期待主从同步实现能力返回
- 数据读从库,主从同步实现就能读到最新数据
这种计划,咱们只须要批改数据库之间同步配置即可,业务层无需批改,绝对简略。
不过,因为主库写须要期待主从实现,写申请的时延将会减少,吞吐量将会升高。
这一点对于当初在线业务,可能无奈承受。
选择性强制读主
对于须要强统一的场景,咱们能够将其的读申请都操作主库,这样读写都在主库,就没有不统一的状况。
这种计划业务层须要革新一下,将其强制性读主,绝对革新难度较低。
不过这种计划绝对于节约了另一个数据库,减少主库的压力。
中间件抉择路由法
这种计划须要应用一个中间件,所有数据库操作都先发到中间件,由中间件再散发到相应的数据库。
这时流程如下:
- 写申请,中间件将会发到主库,同时记录一下此时写申请的 key(操作表加主键等)
- 读申请,如果此时 key 存在,将会路由到主库
- 肯定工夫后(经验值),中间件认为主从同步实现,删除这个 key,后续读将会读从库
这种计划,能够保持数据读写的统一。
然而零碎架构减少了一个中间件,整体复杂度变高,业务开发也变得复杂,学习老本也比拟高。
缓存路由大法
这种计划与中间件的计划流程比拟相似,不过革新老本绝对较低,不须要减少任何中间件。
这时流程如下:
- 写申请发往主库,同时缓存记录操作的 key,缓存的生效工夫设置为主从的延时
读申请首先判断缓存是否存在
- 若存在,代表刚产生过写操作,读申请操作主库
- 若不存在,代表近期没产生写操作,读申请操作从库
这种计划绝对中间件的计划老本较低,然而呢咱们此时又引入一个缓存组件,所有读写之间就又多了一步缓存操作。
总结
咱们引入主从架构,数据读写拆散,目标是为了解决业务疾速倒退,申请质变大,并发质变大,从而引发的数据库的读瓶颈。
不过当引入新一个架构解决问题时,势必会带来另外一个问题,数据库读写拆散之后,主从提早从而导致数据不统一的状况。,
为了解决主从提早,数据不统一的状况,咱们能够采纳以下这几种计划:
- 忍耐大法
- 数据库同步写计划
- 选择性强制读主
- 中间件抉择路由法
- 缓存路由大法
下面的计划都有各自的长处,当然也有相应的毛病,咱们须要依据本人的业务状况,抉择相应的解决方案。
好了,明天的文章就到此。
我是楼下小黑哥,下周见~
参考链接
- 数据库主从不统一,怎么解?
欢送关注我的公众号:小黑十一点半,取得日常干货推送。如果您对我的专题内容感兴趣,也能够关注我的博客:studyidea.cn