本文主要讲解“数据库中读写分离的坑有哪些”。本文的讲解内容简单明了,易学易懂。请跟随边肖的思路学习和学习“数据库里读写分离的坑有哪些”。
前言
事情是这样的,我刚加入公司的时候,就收到了这样一个业务需求:
每个支付渠道在无法支付时都会返回一个特定的错误代码。内部业务需要将通道特定的错误代码转义为内部错误代码,这样我们就可以将自己的错误代码统一返回给外界。
这个要求其实并不难。当时设计的系统架构如下:
添加规则的过程简单地分为三个步骤:
业务人员通过管理后台添加映射规则。
在数据库中添加和修改此映射规则。
删除缓存
这里添加缓存的原因是在这个场景中需要使用每一笔支付。使用缓存可以避免每次从数据库中读取,提高读取速度。
后续付款申请业务流程如下:
数据库读写分离-用户操作。
当缓存中的映射规则不存在时,将查询数据库,然后将其加载到缓存中。如果缓存内映射规则已经存在,将直接使用缓存内映射规则。
其实这个业务流程比较简单。当时测试环境没有问题,但是后续发布的上线环境遇到了奇怪的问题。
"添加规则后,映射规则在一段时间内没有生效。查看日志,发现查询数据库时没有数据。」
这很奇怪。日志显示添加成功,但是查询没有数据。然而,过了一会儿,数据又被发现了。
检查代码后,我发现没有任何问题。第二天上班的时候,还没搞清楚问题的原因就咨询了同事:
原在线数据库采用主从式架构,数据读写分离,从数据库中进行数据查询。数据写入是直接操作主库,然后同步到从库。
“由于数据库同步的延迟,在这段数据同步期间,主从数据会不一致,无法从数据库中找到最新的数据。」
如果你之前的数据库系统架构是单数据库或者主备架构,当你第一次切换到数据读写分离架构的时候,这个坑很可能会被踩。
数据库系统架构发展
我们先了解一下数据库系统架构,最后看看如何解决主从同步延迟带来的数据不一致。
主备架构
在业务发展初期,数据访问量较小,可以直接采用单一数据库架构。
但是,我们通常不使用上述体系结构,因为存在单点问题。如果数据库出现故障,在此期间业务将不可用。除了等待重启,我们没有其他解决方案。
因此,我们将添加一个备份库来实时同步主库的数据。
主/备用架构
一旦“主库”出现故障,手动启动“主机”,将“备用库”更改为“主机”,以继续提供服务。
这种架构易于部署和维护,业务开发不需要任何改造。
但是缺点很明显,因为备份库只有在主库出现问题时才会启用,存在一定的资源浪费。
主从架构
随着业务的发展,请求量越来越大,数据量也越来越大,业务越来越复杂,很快数据就会达到瓶颈。
因为大多数企业读得多写得少,数据库读取最有可能成为系统的瓶颈。
这时,我们可以提高阅读成绩。此时可以采用增加从实例、主从同步、数据读写分离的方案。
可以看出,这种架构与主从架构没有什么不同。主要区别在于主从架构下,从库需要时刻工作,就像主库一样。主库提供写服务,从库只提供读服务。
如果后续阅读的压力还是太大,我们也可以增加从库数量,横向扩展阅读能力
p>
在这延时窗口期内,从库的读只能读到一个旧数据,这也是上面案例问题的真正的原因。
接下来我们来看下有什么办法可以优化这种情况。
主从延时解决办法
忍受大法
第一种解决办法,很简单,无他,不管他,没有读到也没事。这时业务不需要任何改造,你好,我好,她也好~
如果业务对于数据一致性要求不高,我们就可以采用这种方案。
数据同步写方案
主从数据同步方案,一般都是采用的异步方式同步给备库。
我们可以将其修改为同步方案,主从同步完成,主库上的写才能返回。
-
业务系统发起写操作,数据写主库
-
写请求需要等待主从同步完成才能返回
-
数据读从库,主从同步完成就能读到最新数据
这种方案,我们只需要修改数据库之间同步配置即可,业务层无需修改,相对简单。
「不过,由于主库写需要等待主从完成,写请求的时延将会增加,吞吐量将会降低。」
这一点对于现在在线业务,可能无法接受。
选择性强制读主
对于需要强一致的场景,我们可以将其的读请求都操作主库,这样「读写都在主库」,就没有不一致的情况。
这种方案业务层需要改造一下,将其强制性读主,相对改造难度较低。
不过这种方案相对于浪费了另一个数据库,增加主库的压力。
中间件选择路由法
这种方案需要使用一个中间件,所有数据库操作都先发到中间件,由中间件再分发到相应的数据库。
这时流程如下:
-
写请求,中间件将会发到主库,同时记录一下此时写请求的 key(操作表加主键等)
-
读请求,如果此时 key 存在,将会路由到主库
-
一定时间后(经验值),中间件认为主从同步完成,删除这个 key,后续读将会读从库
这种方案,可以保持数据读写的一致。
但是系统架构增加了一个中间件,整体复杂度变高,业务开发也变得复杂,学习成本也比较高。
缓存路由大法
这种方案与中间件的方案流程比较类似,不过改造成本相对较低,不需要增加任何中间件。
这时流程如下:
-
写请求发往主库,同时缓存记录操作的 key,缓存的失效时间设置为主从的延时
-
读请求首先判断缓存是否存在
-
若存在,代表刚发生过写操作,读请求操作主库
-
若不存在,代表近期没发生写操作,读请求操作从库
这种方案相对中间件的方案成本较低,但是呢我们此时又引入一个缓存组件,所有读写之间就又多了一步缓存操作。
感谢各位的阅读,以上就是“数据库读写分离的坑有哪些”的内容了,经过本文的学习后,相信大家对数据库读写分离的坑有哪些这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是,小编将为大家推送更多相关知识点的文章,欢迎关注!
内容来源网络,如有侵权,联系删除,本文地址:https://www.230890.com/zhan/41734.html