首页 > 数据库 >【Redis】Redis 生产问题。如何确保缓存和数据库数据的一致性? 常见的缓存更新策略?

【Redis】Redis 生产问题。如何确保缓存和数据库数据的一致性? 常见的缓存更新策略?

时间:2024-03-30 21:01:37浏览次数:15  
标签:缓存 数据库 Redis 布隆 更新 一致性 数据

目录

缓存穿透

缓存穿透解决办法

缓存击穿

击穿解决办法?

缓存穿透和缓存击穿的区别?

缓存雪崩

雪崩解决办法?

如何确保缓存和数据库数据的一致性?

常见的缓存更新策略?


缓存穿透

定义:缓存穿透说简单点就是大量请求的 key 是不合理的,根本不存在于缓存中,也不存在于数据库中 。这就导致这些请求直接到了数据库上,根本没有经过缓存这一层,对数据库造成了巨大的压力,可能直接就被这么多请求弄宕机了。

缓存穿透解决办法

1.最基本的就是首先做好参数校验,一些不合法的参数请求直接抛出异常信息返回给客户端。比如查询的数据库 id不能小于 0、传入的邮箱格式不对的时候直接返回错误消息给客户端等等。

2.缓存空值或者默认值

可以针对查询的数据,在缓存中设置一个空值或者默认值,这样后续请求就可以从缓存中读取到空值或者默认值,返回给应用,而不会继续查询数据库。

3.采用布隆过滤器

可以在写入数据库数据时,使用布隆过滤器做个标记,然后在用户请求到来时,业务线程确认缓存失效后,可以通过查询布隆过滤器快速判断数据是否存在,如果不存在,就不用通过查询数据库来判断数据是否存在。即使发生了缓存穿透,大量请求只会查询 Redis 和布隆过滤器,而不会查询数据库,保证了数据库能正常运行,Redis 自身也是支持布隆过滤器的。

布隆过滤器的工作过程:

布隆过滤器由「初始值都为 0 的位图数组」和「 N 个哈希函数」两部分组成。当我们在写入数据库数据时,在布隆过滤器里做个标记,这样下次查询数据是否在数据库时,只需要查询布隆过滤器,如果查询到数据没有被标记,说明不在数据库中。

布隆过滤器会通过 3 个操作完成标记:

  • 第一步,使用 N 个哈希函数分别对数据做哈希计算,得到 N 个哈希值;

  • 第二步,将第一步得到的 N 个哈希值对位图数组的长度取模,得到每个哈希值在位图数组的对应位置。

  • 第三步,将每个哈希值在位图数组的对应位置的值设置为 1;

布隆过滤器由于是基于哈希函数实现查找的,高效查找的同时存在哈希冲突的可能性,所以,查询布隆过滤器说数据存在,并不一定证明数据库中存在这个数据,但是查询到数据不存在,数据库中一定就不存在这个数据。

缓存击穿

缓存击穿中,请求的 key 对应的是 热点数据 ,该数据 存在于数据库中,但不存在于缓存中(通常是因为缓存中的那份数据已经过期) 。这就可能会导致瞬时大量的请求直接打到了数据库上,对数据库造成了巨大的压力,可能直接就被这么多请求弄宕机了。

击穿解决办法?
  • 设置热点数据永不过期或者过期时间比较长。

  • 针对热点数据提前预热,将其存入缓存中并设置合理的过期时间比如秒杀场景下的数据在秒杀结束之前不过期。

  • 互斥锁方案,保证同一时间只有一个业务线程更新缓存,未能获取互斥锁的请求,要么等待锁释放后重新读取缓存,要么就返回空值或者默认值。

缓存穿透和缓存击穿的区别?

缓存穿透中,请求的 key 既不存在于缓存中,也不存在于数据库中。

缓存击穿中,请求的 key 对应的是 热点数据 ,该数据 存在于数据库中,但不存在于缓存中(通常是因为缓存中的那份数据已经过期)

缓存雪崩

实际上,缓存雪崩描述的就是这样一个简单的场景:缓存在同一时间大面积的失效,导致大量的请求都直接落到了数据库上,对数据库造成了巨大的压力。 这就好比雪崩一样,摧枯拉朽之势,数据库的压力可想而知,可能直接就被这么多请求弄宕机了。

雪崩解决办法?

针对 Redis 服务不可用的情况:

  1. 采用 Redis 集群,避免单机出现问题整个缓存服务都没办法使用。

  2. 限流,避免同时处理大量的请求。

针对热点缓存失效的情况:

  1. 将缓存失效时间随机打散: 我们可以在原有的失效时间基础上增加一个随机值(比如 1 到 10 分钟)这样每个缓存的过期时间都不重复了,也就降低了缓存集体失效的概率。

  2. 缓存永不失效(不太推荐,实用性太差)。

  3. 设置二级缓存。

如何确保缓存和数据库数据的一致性?

  • 缓存延时双删:

1 先删除缓存 2 再更新数据库 3 休眠一会(比如1秒),再次删除缓存。

  • 删除缓存重试机制:

  1. 写请求更新数据库

  2. 缓存因为某些原因,删除失败

  3. 把删除失败的key放到消息队列

  4. 消费消息队列的消息,获取要删除的key

  5. 重试删除缓存操作

  • 更新时删除缓存:在更新数据库中的数据时,先更新数据库,然后再删除 Redis 缓存中对应的数据。当下一个请求访问缓存时,会发现缓存失效,从数据库中读取最新的数据,并将其写入 Redis 缓存。这种方式可以保证在数据库更新后,下一次读取会获取到最新的数据。

  • 使用事务:Redis 支持事务操作,可以将数据库更新和 Redis 缓存更新放在一个事务中执行。这样可以确保数据库和缓存的更新操作要么同时成功,要么同时失败,保持数据一致性。

  • 发布/订阅模式:使用发布/订阅模式(Pub/Sub)或消息队列(Message Queue)来实现缓存和数据库之间的数据同步。当数据库中的数据发生变化时,发布一个消息通知缓存更新对应的数据。缓存接收到消息后,更新对应的数据,从而保持一致性。

  • 双写策略:在某些情况下,可以选择将数据同时写入数据库和缓存,而不是更新策略中的先后顺序。这样可以保证数据的一致性,但也增加了写入的开销和复杂性。

常见的缓存更新策略?

常见的缓存更新策略共有3种:

  • Cache Aside(旁路缓存)策略;

  • Read/Write Through(读穿 / 写穿)策略;

  • Write Back(写回)策略;

实际开发中,Redis 和 MySQL 的更新策略用的是 Cache Aside,另外两种策略应用不了。

旁路缓存策略:

Cache Aside(旁路缓存)策略是最常用的,应用程序直接与「数据库、缓存」交互,并负责对缓存的维护,该策略又可以细分为「读策略」和「写策略」。

写策略的步骤:

  • 先更新数据库中的数据,再删除缓存中的数据。

读策略的步骤:

  • 如果读取的数据命中了缓存,则直接返回数据;

  • 如果读取的数据没有命中缓存,则从数据库中读取数据,然后将数据写入到缓存,并且返回给用户。

注意,写策略的步骤的顺序不能倒过来,即不能先删除缓存再更新数据库,原因是在「读+写」并发的时候,会出现缓存和数据库的数据不一致性的问题。

标签:缓存,数据库,Redis,布隆,更新,一致性,数据
From: https://blog.csdn.net/2301_79456272/article/details/137182975

相关文章

  • Redis
    Redis1、Nosql概述大数据时代大数据一般的数据库无法进行分析处理1.1、为什么要用Nosql1、单机MySQL的年代!2、Memcached(缓存)+MySQL+垂直拆分(读写分离)网站80%的情况都在读,每次去查询数据库就十分麻烦!所以为了减轻数据的压力,我们可以使用缓存来保证效率!发展过程:优......
  • 使用Docker搭建Redis Cluster集群
    Cluster模式是Redis的一种高级集群模式,它通过数据分片和分布式存储实现了负载均衡和高可用性。在Cluster模式下,Redis将所有的键值对数据分散在多个节点上。每个节点负责一部分数据,称为槽位。通过对数据的分片,Cluster模式可以突破单节点的内存限制,实现更大规模的数据存储。Redis......
  • 消息队列,缓存,分库分表是高并发解决方案
    消息队列的七种经典应用场景 在笔者心中,消息队列,缓存,分库分表是高并发解决方案三剑客。在职业生涯中,笔者曾经使用过ActiveMQ、RabbitMQ、Kafka、RocketMQ这些知名的消息队列。这篇文章,笔者结合自己的真实经历,和大家分享消息队列的七种经典应用场景。1异步&解耦笔......
  • Java 实现缓存的三种方式
    Java实现缓存的三种方式文章目录Java实现缓存的三种方式一、`HashMap`实现缓存`Step-1`:实现一个缓存管理类`Step-2`:将缓存管理类交给`Spring`进行管理`Step-3`:编写接口测试缓存`Step-4`:结果展示二、`guavalocalcache`实现`Step-1`:导入`guava`依赖`Step-2`:使用`......
  • redis面试题-持续更新~
    1、我没有执行bgsave条件,执行了shutdown之后,数据会不会丢?不会丢,因为只要执行shutdown会默认,会先执行一条bgsave。 2、kill-9会丢数据,kill不会丢数据,为什么?kill-9比较暴力,直接把父进程砍掉了,kill(或者pkill)会让redis把活干完(可以理解为kill为正常的推出流程,和前面......
  • Sentinel 的QPS限流和Redis流量风控
    目录Sentinel的QPS限流导入依赖:这个限制的时每秒的QPS为1:如果触发风控,设置降级策略。在代码中引入Sentinel注解控制流控规则。用Redis实现流量风控:lua脚本如下:配置过滤器器执行lua脚本,判断访问次数是否超过:我们可以通过这个过滤器得知,再timeWindow时间内,我们的访......
  • Linux架构27 Ansible变量, 定义变量的方式, 变量注册, facts缓存
    Ansible变量一、变量概述变量提供了便捷的方式来管理Ansibleplaybook的每一个项目中的动态值,比如nginx-1.6.3这个软件包的版本,在其他地方或许会反复使用,那么如果讲此值设置为变量,然后再在其他的playbook中调用,会方便许多。如此一来还方便维护,减少维护的成本。二、定义变量的......
  • android小球(二)——用户数据缓存详解SharedPreferences
    SharedPreferences概述SharedPreferences是Android平台上一个轻量级的存储辅助类,用来保存应用的一些常用配置,它提供了String,set,int,long,float,boolean六种数据类型。使用SharedPreferences进行存储的数据是存放在一个XML文件中的,同时它的存储方式是是以key-value的形式,key对应......
  • Redis Map数据结构中相同key不同的字段会分散多节点存储吗?
    目录结论说明 结论   无论是单实例Redis还是Redis集群,一个Map数据类型的key对应的所有字段和值都存储在同一台机器上。在Redis集群中,这是通过哈希槽机制来保证的,确保了对同一个key的操作不需要跨节点通信,从而提高了操作的效率。说明    Redis的Map数据类......
  • 美团一面:项目中使用过Redis吗?我说用Redis做缓存。他对我哦了一声
    引言Redis,作为一种开源的、基于内存且支持持久化的键值存储系统,以其卓越的性能、丰富灵活的数据结构和高度可扩展性在全球范围内广受欢迎。Redis不仅提供了一种简单直观的方式来存储和检索数据,更因其支持数据结构如字符串、哈希、列表、集合、有序集合等多种类型,使得其在众多场景......