自学内容网 自学内容网

Redis--如何保障缓存数据库一致性?(面试高频问题)

数据库和缓存不一致采用什么方案?

选取方案:缓存调用者在更新完数据库后再去更新缓存,也称之为双写方案。

操作缓存和数据库时有三个问题需要考虑:

  • 删除缓存还是更新缓存?

    • 更新缓存:每次更新数据库都更新缓存,无效写操作较多
    • 删除缓存:更新数据库时让缓存失效,查询时再更新缓存
  • 如何保证缓存与数据库的操作的同时成功或失败?

    • 单体系统,将缓存与数据库操作放在一个事务
    • 分布式系统,利用TCC等分布式事务方案
  • 先操作缓存还是先操作数据库?

    • 先删除缓存,再操作数据库
    • 先操作数据库,再删除缓存

我们应当是先操作数据库,再删除缓存,原因在于,在两个线程并发来访问时,假设线程1先来,他先把缓存删了,此时线程2过来,他查询缓存数据并不存在,此时他写入缓存,当他写入缓存后,线程1再执行更新动作时,实际上写入的就是旧的数据,新的数据被旧数据覆盖了。
在这里插入图片描述

实现商铺和缓存与数据库双写一致

背景

点评项目的店铺数据因为会被高频访问,所以数据存了两份:MySQL 数据库和 Redis 缓存中。

但是在店铺创建后,进行修改时,需要同时对两者进行变更,因为种种异常原因,如何保障数据库和缓存种短链接的一致性呢?

点评项目使用了什么策略?

根据id查询店铺时,如果缓存未命中,则查询数据库,将数据库结果写入缓存,并设置超时时间。
根据id修改店铺时,先修改数据库,再删除缓存。
修改重点代码1:修改ShopServiceImpl的queryById方法

设置redis缓存时添加过期时间
在这里插入图片描述
修改重点代码2
代码分析:通过之前的淘汰,我们确定了采用删除策略,来解决双写问题,当我们修改了数据之后,然后把缓存中的数据进行删除,查询时发现缓存中没有数据,则会从mysql中加载最新的数据,从而避免数据库和缓存不一致的问题
在这里插入图片描述

总结:这种方法实现比较简单,不依赖额外中间件,比较适合系统并发不高的情况使用。

存在什么问题?

  1. 极端情况下的数据不一致

会存在一个很小周期的缓存与数据库不一致的情况,不过对于绝大多数的情况来说,是可以容忍的。除去一些电商库存、列车余票等对数据比较敏感的情况,比较适合绝大多数业务场景。

  1. 缓存是否能删除?

再思考一个问题,缓存删除真的合适么?在涉及海量并发的场景中,如果程序删除了缓存,可能会导致缓存击穿问题,而更新频繁时则可能引发缓存雪崩。

因此,在考虑缓存一致性模型时,务必充分考虑业务场景是否属于高并发模型。如果是高并发场景,删除缓存可能并不合适,此时应采用最终一致性策略。

那就应该引发出来 Canal 配合 Binlog 的形式解决缓存和数据库最终一致性问题。

下面提一些保证一致性的办法

当面试官问你:redis做为缓存,MySQL的数据如何与redis进行同步呢?(双写一致性问题)
回答一定要设置前提,先介绍自己的业务背景:高一致性要求还是允许延迟一致。

延迟双删(强一致场景)

  • 读操作:如果缓存未命中,则查询数据库,将数据库结果写入缓存,并设置超时时间。
  • 写操作:延迟双删
    在这里插入图片描述
    为什么删除两次缓存?
    因为在线程1删除缓存后,更新数据库的期间,线程2查询数据库又更新缓存会出不一致。
    为什么设置延时?
    休眠 1 秒再次淘汰缓存,可以将 1 秒内造成的缓存脏数据再次删除

在这里插入图片描述

分布式锁(强一致场景)

更新 DB 时同样更新 cache,保证在一个事务中,通过加锁来保证更新 cache 时不存在线程安全问题
问题:性能低
在这里插入图片描述

异步通知(强一致场景)

基于 MQ 的异步通知

对数据的修改后,代码需要发送一条消息到 MQ 中,缓存服务监听 MQ 消息
在这里插入图片描述

Canal配合binlog

Cannal是基于MySQL主从同步来实现的。
在这里插入图片描述


原文地址:https://blog.csdn.net/m0_51275144/article/details/144795821

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!