gd减光片 0.9db什么意思什么意思(减光片 0.9db什么意思)

最近组内在进行稳定性建设,其中一个重要的内容就是缓存建设,包含富客户端、命中率提升、一致性保障等多个模块。今天就老生常谈下缓存DB一致性保障。

组内目前DB采用的是MySQL,缓存采用的是redis,下面就分别使用这两个组件作为DB和缓存举例。

为什么会不一致

两个不同的组件,分布在不同的服务实例上,各自的数据更新没有事务保障,所以当数据变更时,无论先操作数据库还是先操作缓存,只要后面的操作失败,就会出现不一致。

gd减光片 0.9db什么意思什么意思(减光片 0.9db什么意思)

分布式服务的高可用要求下,不管是MySQL还是redis都不会是单机单实例部署,比如MySQL是主从模式,redis集群也有主备实例,哨兵监测。那当MySQL主从同步失败或者redis写入后发生主备切换,此时数据也会出现不一致。

gd减光片 0.9db什么意思什么意思(减光片 0.9db什么意思)

gd减光片 0.9db什么意思什么意思(减光片 0.9db什么意思)

最终一致 vs 强一致

强一致的含义简单来说就是本应用在任何对外提供服务的时间点,缓存和DB的数据都是一致的;而最终一致则允许存在一定的数据不一致时间窗口。

如果要求强一致,则直到确认缓存和DB都操作成功前不能对外提供服务,类似于读写互斥。这不太符合缓存的应用场景,一般只有上游的读流量较高才会引入缓存来减少DB的压力,如果读写互斥,写请求期间会阻塞大量读请求,甚至写请求因为网络等原因无法完成时还会造成服务不可用,相当于CAP中牺牲了A。

目前来看缓存是没有这样的应用场景的,所以既然用了缓存,数据一致性考虑指的就是最终一致性。

删除缓存 vs 更新缓存

当数据发生变更的时候,到底应该删除缓存还是更新缓存?这个需要根据具体情况分析:

缓存数据计算复杂度

如果缓存的数据只是数据库记录的简单拷贝,将数据库数据转换成缓存数据无需进行复杂的计算,更新和删除的成本就没有太大区别。

gd减光片 0.9db什么意思什么意思(减光片 0.9db什么意思)

但如果缓存中存的是数据库数据经过一系列加工计算的结果值,那更新缓存前就需要经过一系列复杂的计算,会加大写请求的响应。如果删除缓存则无需这步操作(转移到了读请求或者定时刷新任务中)。

gd减光片 0.9db什么意思什么意思(减光片 0.9db什么意思)

缓存命中率

除了定时全量刷新的场景,一般读请求的处理是:先读缓存,读到直接返回;读不到缓存读DB,然后将DB的数据放入缓存中再返回。

gd减光片 0.9db什么意思什么意思(减光片 0.9db什么意思)

如果在数据变更的时候执行的是删除缓存,则至少会存在一次读请求的cache miss,至少一次的意思是,如果不做并发锁控制(一般也不会做),可能存在同一时间的多个读请求都没命中缓存,从而读DB。而更新缓存则没有这个问题,只要缓存没有自然失效,则读请求都能命中。

所以更新缓存比删除缓存有着更高的缓存命中率。

写操作并发度

如果针对同一个缓存key的数据写请求是串行的,那不管是更新缓存还是删除缓存,都不会有问题。但如果存在并行的情况,那更新缓存的场景有可能造成缓存DB不一致(不管先操作数据库还是先操作缓存),而删除缓存不会。以先操作数据库举例:

gd减光片 0.9db什么意思什么意思(减光片 0.9db什么意思)

读请求量

一般来说缓存的应用场景是读多写少,极端场景下,比如某个主播预约了秒杀活动,则同一时间点某个key的请求量会非常大,也就是热key。如果此时未禁止数据变更,那删除缓存的后果是非常严重的,大量请求透传到数据库会瞬间打挂数据库;但如果是更新缓存则不会有这个问题。

失败重试

假设更新或者删除缓存失败了,此时缓存和DB的数据是不一致的,我们希望程序有一定的自愈能力,比如说通过重试来保证数据一致。从一致性角度考虑的话,删除缓存是可以一直重试的,但是更新缓存就不一定了。如果重试期间数据又被更改了,那就不能拿之前的数据去更新缓存,相对保险的做法是更新缓存前反查一次DB,但这一方面只是缩小了概率,另一方面多次重试加大了对DB的压力。

数据量

如果每次数据发生变更,都执行更新缓存,但是缓存中的数据不一定会被马上读取,此时会导致缓存中存放了很多不常访问的数据,缓存空间存在一定的浪费,但一般来说这个不是什么大问题。

如何选择

一般来说,删除缓存是更通用的方案,因为造成数据不一致的概率会比更新缓存小。但如果业务qps非常高,命中率降低对DB的压力影响很大,那可以考虑更新缓存,至于数据一致性,需要通过其他辅助措施来保障。

先操作数据库 vs 先操作缓存

既然数据库和缓存是独立的组件,那操作就需要分个先后,而基于网络的不确定性,数据库和缓存都是有可能操作失败的。以删除缓存举例(更新缓存类似):

先删除缓存,然后更新数据库

  • 异常情况——更新数据库失败

如果缓存删除成功了,数据库更新失败,那么此时缓存中无值,但数据库中是旧值,类似于请求失败了,不存在数据不一致的问题,直接返回失败让上游重试即可。

  • 正常情况

在一般读多写少的场景下,写操作的同时存在读请求是比较普遍的情况,此时会有数据不一致的可能性。

gd减光片 0.9db什么意思什么意思(减光片 0.9db什么意思)

先更新数据库,然后删除缓存

  • 异常情况——删除缓存失败

如果数据库更新成功了,缓存删除失败,那么此时数据库中是最新值,缓存中是旧值。之后的读请求读到的都是旧数据,只有当缓存失效后,才能从数据库中得到正确的值。

  • 正常情况

同样考虑读写并发的情况,也是存在最终数据不一致的可能性的。

gd减光片 0.9db什么意思什么意思(减光片 0.9db什么意思)

但这种情况需要同时满足3个条件:

  1. 缓存刚好失效
  2. 读写请求并发
  3. 更新数据库 + 删除缓存的时间,要比读数据库 + 写缓存时间短

1+2是小概率事件,3又是小概率事件,所以实际当中这种情况非常罕见。当然,如果MySQL采用的是主从架构且读的是从库,那概率会稍微大一点,因为写请求更新完数据库后读请求依然可能读到旧值(因为主从同步未完成)。

如何选择

异常情况相比正常情况是小概率,对于先删除缓存来说需要考虑的是正常情况中读写并发场景有可能导致的问题;对于先更新数据库来说需要考虑的是异常情况,以及正常情况中极低概率的不一致问题。

因为异常情况比较好识别,之后程序通过其他手段辅助处理,所以从实际经验来看,先更新数据库,之后删除缓存是更常见通用的方案。但因为两种方式都存在一定的缺陷,所以对于一致性要求较高的场景来说,辅助手段都是少不了的。

解决方案

方案一:过期时间

最简单的一个方案,通过设置缓存key的过期时间来达到缓存自动失效的目的,读请求在读不到缓存的时候查询DB数据再存入缓存,而数据更新的时候完全不需要考虑缓存,只需要对数据库进行更新即可。

  • 读请求
gd减光片 0.9db什么意思什么意思(减光片 0.9db什么意思)

  • 写请求
gd减光片 0.9db什么意思什么意思(减光片 0.9db什么意思)

优点

  1. 实现方式简单,管理成本低。

不足

  1. 过期时间不容易确定,太长拉长了数据不一致的时间窗口,太短影响命中率失去了缓存意义。

一般适用于对数据延迟不敏感的业务场景,更多的是作为其他方案的兜底措施。

方案二:主动删除或者更新

在方案一的基础上扩展,缓存key的过期时间作为兜底,同时业务代码在更新数据库的时候,执行更新或者删除缓存的操作。

  • 读请求

和方案一相同

  • 写请求
gd减光片 0.9db什么意思什么意思(减光片 0.9db什么意思)

优点

  1. 正常情况下,数据不一致的时间窗口小;
  2. 方案较简单,实现不复杂。

不足

  1. 如果更新数据库成功,更新缓存却失败,不一致时间拉长,需要缓存过期时间兜底;
  2. 根据上面的先操作数据库后操作缓存部分,读写并发场景下存在小概率导致数据不一致。

方案三:延时双删

在方案二的基础上进行了扩展,增加了延时删除的操作,其实原理类似于失败重试。如果是延时更新,那少不了DB反查,而且从理论角度来说,反查和更新又有并发的可能性,所以不是有特殊考虑,一般是延时删除。

  • 读请求

和方案一相同

  • 写请求
gd减光片 0.9db什么意思什么意思(减光片 0.9db什么意思)

优点

  1. 只要两次缓存删除操作成功一次,数据不一致的时间窗口就很小;
  2. 一般延时删除采用异步线程,多一步放入队列的操作对性能几乎没影响;
  3. 方案二的不足中,两个导致数据不一致情况的概率都被缩小了。

不足

  1. 如果延时删除缓存失败,还是需要缓存过期时间兜底;
  2. 延迟的时间需要根据具体业务确定,一般只能给出经验值;
  3. 比方案二复杂一点,需要引入延时队列和额外线程;
  4. 虽然在方案二基础上进一步降低了数据不一致概率,但还依然都存在。

一般来说延迟的时间会在秒级别,比如1-2秒,主要参考的是读请求的执行时间。如果第二次执行删除缓存在读请求数据放入缓存之后,则解决了此时情况导致的数据不一致。

gd减光片 0.9db什么意思什么意思(减光片 0.9db什么意思)

方案四:使用mq异步删除

在方案三的基础上进行了扩展,方案三中有一个问题是第二次删除缓存依然存在失败的可能性,所以可以通过增加重试次数来进一步降低删除失败的概率。可以引入mq中间件来实现,如果在应用服务中实现这个逻辑,会降低服务的稳定性和增加服务的复杂度。

  • 读请求

和方案一相同

  • 写请求
gd减光片 0.9db什么意思什么意思(减光片 0.9db什么意思)

优点

  1. 只要消息发送成功,通过消息中间件的重试,基本能保证删除缓存操作的执行成功。

不足

  1. 如果消息只尝试发送一次,则发送失败会退化为方案一,可以考虑消息发送失败的重试;
  2. 引入了消息中间件,方案复杂度更高。

这里第2步删除缓存需要视业务情况定,如果对正常情况下数据不一致的窗口没有很高的要求,可以将第2步去掉,直接通过第3步来保证缓存的删除。

如果第2步执行成功第3步就不执行,那其实只是解决了方案二中的第1点不足,第2点依然存在且概率相同。

方案五:监听binlog执行删除

对于业务代码来说,数据一致性是跟业务无关的逻辑,如果方案四中省略了第2步,则可以再将发送消息这一步做个变化,直接通过binlog来触发这个逻辑。

  • 读请求

和方案一相同

  • 写请求
gd减光片 0.9db什么意思什么意思(减光片 0.9db什么意思)

优点

  1. 保留了方案四的优点,且将数据一致的逻辑从业务中解耦。

不足

  1. 包含组件较多,方案复杂;
  2. 如果缓存结构和DB表不是一一对应,则不太好处理。

写在最后

其实每个方案都有各自的适用场景,从方案一到方案五,基本上一致性的保障是越来越高,但方案的复杂度也是越来越高,具体取舍就要看真正的业务使用场景了。就像Linux的Page Cache使用的写后缓存模式(Write behind caching Pattern),上层只需将数据写入缓存,具体的落盘由异步线程处理,这对性能是一个巨大的提升,但是如果机器异常关机,数据是有可能丢失的。

每个组件的可用性都做不到100%,虽然引入更多组件会增加方案复杂性,但同时也能将数据不一致的概率进一步降低,根据业务做好平衡,附上最后我们采用的一个一致性保障方案,其中对账服务是利用已有的平台进行接入。

gd减光片 0.9db什么意思什么意思(减光片 0.9db什么意思)

创业项目群,学习操作 18个小项目,添加 微信:80709525  备注:小项目

本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 sumchina520@foxmail.com 举报,一经查实,本站将立刻删除。
如若转载,请注明出处:https://www.vsaren.org/2326.html