缓存与数据库数据一致性探索

缓存使用

目前大家利用缓存都是提前缓存数据,然后到了爆发点,比如双11零点,用户大量访问,先命中缓存,缓存没有的话,再去查库,查到数据后,再把数据缓存起来,下一次就可以命中。

问题:一致性

我们经常使用缓存,更新缓存一般都是在修改数据库成功后执行刷缓存操作,但有没有可能出现失败?
在这里插入图片描述

  • 更新数据库成功,缓存覆盖问题
    高并发情况下的,刷缓存都会存在缓存覆盖的问题,因为刷缓存要先查再塞到缓存中,那么这个时候可能查到旧数据塞进缓存中,导致缓存是旧数据。因为当前的处理逻辑是没有顺序的

当出现缓存不一致性的问题,那怎么解决?有人提出删除缓存,但依旧有问题:

  • 更新DB之前,删除缓存
    这个时候如果更新DB还没成功,突然来一条查询逻辑,则查询到老数据,放到缓存里,不合适
  • 更新DB之后,删除缓存
    更新之后,删除缓存,并发下查询的请求会污染缓存,旧数据被查出来,缓存被删除,正好塞到缓存里。
问题解析

这里主要是2方面的并发问题:

  • 更新DB的一致性
    更新DB一般都是高并发场景下,
  • 刷缓存的一致性
    刷缓存有2方面,一方面是修改DB后的刷缓存,另一个方面是查询库并将数据插入缓存的

在数据一致性的场景下,需要考虑上述2个并发性问题。目前有2种方法来解决。

1、版本号

缓存不一致,主要是解决缓存数据是最新的,而不是老数据,于是有人类似cas操作一样,加版本号。我们来假设取缓存的key为key1:

  • 给缓存加上版本号,变动一次,版本加1
    这种类似cas操作,另外设置一个key为key2,对应的value是版本号,更新库之前,先改版本号,版本号定义为数据库的一个版本号,
  • 查缓存
    如果发现缓存里的key2版本号大于key1记录的版本号,则知道key1 缓存是老数据了,我们应该取查库,一直到库数据的版本号跟key2 一样,或者高于key2 的value,才把数据塞入到缓存种,其他情况则读库返回,不存缓存种。

这里可以利用时间来做版本号,数据库每一行有变更时间,如果变更时间比key2 的 value大,则更新数据。

  • 缺点:短期内有较大流量到数据库种,因为穿库请求数据了。
2、加锁控制
  • 给谁加锁
    给key加锁,给更新的商品加一个标识锁,主要是给读逻辑加一个标识符,用来表示这个商品数据处于更改阶段,拿不到这个锁,就不能去执行更新DB操作,直接抛异常,更新DB变成了单线程。
  • 锁多长时间?
    锁一个处理写请求流程的时间,默认1S 或者更长,这个看业务需求
  • 什么时候加锁?
    更新数据之前,删除缓存之前加一个锁,这个锁不会影响后续流程,只是拿到了锁就执行删除缓存,没拿到锁,不用关心缓存的删除问题。
  • 为什么加锁
    加锁主要用于更新缓存,因为缓存被删除,读数据都读库,这个时候判断是否有锁,有锁则不存到缓存里,没锁时,就把数据库数据set到缓存里,这样能保证最新的数据一定会更新到缓存里。

缺点:

  • 锁多久是个问题,万一处理数据库的操作事务特别耗时,则较长时间内,都穿库查询。
  • 而且如果锁超时呢?锁超时就释放锁了,此时操作数据还没有成功,查库老数据存到缓存种。
  • 最大问题QPS,QPS降低了非常多。
    在这里插入图片描述
更新DB 有必要弄成单线程吗?

如果是多线程,就存在一个问题,有可能一个线程A占据了锁,另一个线程B 没有锁,线程A执行结束,但线程B还在执行,线程A执行结束,锁被释放,有一个查询请求来了,查询旧数据到缓存,线程B执行结束,也没有删除缓存的能力,这个时候就会存在不一致的问题,而且是长期不一致。

思考,把加锁+删除缓存 放到更新DB后面

其实是可以的,这样只对缓存的数据做一个加锁,防止乱删除数据,这样没拿到锁的线程就不能删除缓存,这个时候,数据库的数据和缓存确实存在一部分数据库和缓存不一致的情况,因为数据库已经更新完了,但缓存还是旧数据,但很短暂的不一致性,却可以支撑在更新DB过程中数据库的查询压力,毕竟上面的方案在锁的这段时间内,所有查询的数据都是走数据库,压力较大,可以根据业务来看具体的方案设计。

缓存穿透

  • 概念:大量的请求在缓存中没有查询到指定的数据,因此需要从数据库中进行查询,造成缓存穿透。

很多电商设计缓存的时候,缓存没有是不会直接查库的,就认为没有这类数据,防止缓存穿透,因为大家都会提前把数据库有的数据都缓存起来了,一个请求过来,没有命中缓存,那么肯定数据库里也没有数据,比如查询id=2的数据,数据库根本没有id=2的数据,当然你肯定会认为这样会有问题,万一缓存失效的话,怎么办,当然这就是缓存的问题了,正常来说会有定时任务,去定时更新缓存数据,而且数据库变更,也会异步刷新缓存,除非缓存这个中间件工具有问题,不然一般不会有问题的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值