Redis缓存问题:穿透,击穿,雪崩,双写一致性等

这篇具有很好参考价值的文章主要介绍了Redis缓存问题:穿透,击穿,雪崩,双写一致性等。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Redis缓存问题:穿透,击穿,雪崩,双写一致性等

在高并发场景下,数据库往往是最薄弱的环节,我们通常选择使用redis来进行缓存,以起到缓冲作用,来降低数据库的压力,但是一旦缓存出现问题,也会导致数据库瞬间压力过大甚至崩溃,从而导致整个系统崩溃.今天就聊聊常见的redis缓存问题.

缓存击穿

缓存击穿一般指redis中的一个热点数据过期,导致大量请求直接访问数据库的情况,导致数据库瞬间压力过大甚至崩溃.

解决方案:

  1. 设置热点数据永不过期,这是一个不错的方案(要考虑业务特性,体量以及成本),前提是热点数据不能频繁发生改变,否则就会出现缓存污染.最好是根据一定的策略进行定时更新
  2. 重要接口限流,做好熔断和降级的准备,sentinel是个不错的选择
  3. 使用互斥锁,保证同一时刻只有一个线程可以访问数据库,这何尝不是一种限流呢

缓存穿透

缓存穿透指缓存和数据库中都没有的数据,用户不断发起请求.这种情况最可能就是有人试图恶意攻击系统

解决方案:

  1. 加校验:拦截非法请求,用户鉴权等
  2. redis缓存一个无效值,以防止对同一个key在数据库中的多次查询,但redis中可能会出现大量无效值,导致缓存污染,所以要将有效时间设置得短一些
  3. 添加布隆过滤器,在对数据库进行查询前,先通过布隆过滤器判断是否存在

一般来说这三种方案是同时使用的,第一层一般是校验,拦截部分非法用户和不合理请求(拦截不可能全部拦截而且如果攻击者通过某些方式掌握了大量合法用户呢),第二层是布隆过滤器,尽量避免对数据库的直接访问,但仍然有误判的可能性,第三层再缓存一个无效值,做到尽可能降低风险

缓存雪崩

缓存雪崩一般指reids中大批量数据在极短时间内(同时)过期,导致大量的查询数据库

解决方案:

  1. 在存储数据时,设置过期时间为一个随机值(也可以理解成给固定的过期时间加上一个随机值,类似密码学中的加盐),尽量保证不会有大量数据在同一时间过期
  2. 将热点数据尽量均匀地分布在不同的数据库中
  3. 多级缓存
  4. 设置热点数据永不过期(同缓存击穿中的)

缓存污染

缓存污染指的是缓存中一些只会被访问一次或者几次的的数据,被访问完后,再也不会被访问到,但这部分数据依然留存在缓存中,消耗缓存空间,也会在一定程度上影响redis的性能

redis缓存的maxmemory应该设置多大,这是一个关乎性能和成本的问题,需要根据实际情况进行权衡,但普遍推荐的是设置为总数据量的15%-30%(其他博客都这么写,而且范围还挺大,应该没什么问题🤔)

缓存淘汰策略

官方文档写了8种,如下图:
Redis缓存问题:穿透,击穿,雪崩,双写一致性等,缓存,redis,八股,校招,后端

  • noeviction(不驱逐,即不淘汰)

    默认策略,当缓存达到maxmemory时,redis会拒绝所有写请求,并返回错误信息,此时redis已经进入只读模式,无法再进行写操作,但仍然可以进行读操作

  • allkeys-lru
    所有key采用LRU算法进行淘汰,即优先删除最近最少使用的key

  • allkeys-lfu
    所有key采用LFU算法进行淘汰,即优先删除最不常用的key

  • volatile-lru
    只淘汰设置了过期时间的key,采用LRU算法进行淘汰

  • volatile-lfu
    只淘汰设置了过期时间的key,采用LFU算法进行淘汰

  • allkeys-random
    所有key采用随机删除

  • volatile-random
    只淘汰设置了过期时间的key,采用随机删除

  • volatile-ttl
    删除过期字段设置为true和剩余最短生存时间(TTL)值的密钥。

缓存和数据库一致性

不管是先写MySQL数据库,再删除Redis缓存;还是先删除缓存,再写数据库,都有可能出现数据不一致的情况。举一个例子:如果删除了缓存Redis,还没有来得及写库MySQL,另一个线程就来读取,发现缓存为空,则去数据库中读取数据写入缓存,此时缓存中为脏数据。

更新缓存有四种设计模式: Cache aside, Read through, Write through, Write behind caching

缓存更新模式

Cache Aside(旁路缓存)
  • 失效:应用程序先从cache取数据,没有得到,则从数据库中取数据,成功后,放到缓存中。
  • 命中:应用程序从cache中取数据,取到后返回。
  • 更新:更新数据库, 更新/删除缓存

那么到底是更新缓存还是删除缓存呢?

如果读的频率高, 选择更新缓存, 这样可以提高缓存命中率

如果写的频率高, 选择删除缓存, 等到要读的时候再写入缓存, 可以减少无效的写操作和减少缓存数据量

Read Through(读穿)

Read Through 套路就是在查询操作中更新缓存,也就是说,当缓存失效的时候,Cache Aside是由调用方负责把数据加载入缓存,而Read Through则用缓存服务自己来加载,从而对应用方是透明的。

Write Through(写穿)

Write Through 套路和Read Through相仿,不过是在更新数据时发生。当有数据更新的时候,如果没有命中缓存,直接更新数据库,然后返回。如果命中了缓存,则更新缓存,然后再由Cache自己更新数据库(这是一个同步操作)

Write Behind Caching(写回)

在更新数据的时候,只更新缓存,不更新数据库,而我们的缓存会异步地批量更新数据库。这个设计的好处就是让数据的I/O操作飞快无比(因为直接操作内存嘛 ),因为异步,还可以合并对同一个数据的多次操作,所以性能的提高是相当可观的。但是,其带来的问题是,数据不是强一致性的,而且可能会丢失

一般而言(即不是特殊的业务场景), 我们选用Cache Aside(旁路缓存)模式, 下面我们的讨论也基于此模式.

操作缓存 & 操作数据库,哪个先?

针对删除缓存的情况:

如果采用先删除缓存,在更新数据库,会有什么后果?

  1. 线程A先把缓存的A数据删除,发生上下文切换
  2. 线程B想要读取A数据,发现缓存失效,从数据库读取A数据,并且更新缓存,
  3. 切换回线程A,线程A更新数据库数据。

至此,数据不一致的情况已经出现,数据库的写入较慢,容易出现此现象

先更新数据库,再删除缓存 怎么样?

  1. 线程A读取缓存A数据,发现缓存失效,所以去数据库读取,此时还未写入缓存,发生上下文切换
  2. 线程B更新数据库,并且删除对应的缓存,
  3. 切换回线程A,线程A将读取到的旧值,写入缓存

又出现了数据不一致的情况,但是相比先删除缓存,发生概率小很多,必须同时满足:

  • 读请求的时候,缓存刚好失效
  • 读请求 与 写请求 并发

所以在实际中很难出现请求 B 已经更新了数据库并且删除了缓存,请求 A 才更新完缓存的情况。所以推荐先更新数据库,再删除缓存

还是存在不一致的可能,怎么实现最终的一致性呢?

  1. 延迟双删策略
    延迟双删策略是分布式系统中数据库存储和缓存数据保持一致性的常用策略,但它不是强一致。其实不管哪种方案,都避免不了Redis存在脏数据的问题,只能减轻这个问题,要想彻底解决,得要用到同步锁和对应的业务逻辑层面解决。

不采用先更新数据库,在删除缓存的方案, 而是用先删除缓存,再更新数据库,里面的不一致问题,用延迟双删解决
1、先删除缓存 2、再写数据库 3、休眠500ms(统计线程读取数据和写缓存的时间) (休眠的作用是当前线程等其他线程读完了数据后写入缓存后,删除缓存) 4、再删除缓存

  1. 设置较短的缓存过期时间
    沿用先更新数据库,再删除缓存,就给缓存设置一个较短的过期时间(只要它够短,就不容易读到错误数据)
针对更新缓存的情况:(面试说上面那种即可)

如果采用先更新缓存,再更新数据库

  1. 线程A更新了缓存,此时发生上下文切换
  2. 线程B更新缓存,更新数据库,此时切换回线程A
  3. 线程A更新数据库

此时就出现了数据不一致的现象,数据库的写入较慢,容易出现此现象。

反过来,先更新数据库,再更新缓存呢?

  1. 线程A更新了数据库,还未写入缓存,发生上下文切换
  2. 线程B更新了数据库,并且写入缓存,此时切换到线程A
  3. 线程A把缓存写入,覆盖了之前线程B的缓存

至此,数据不一致的情况,又出现了。缓存的写入通常要远远快于数据库的写入,所以在实际中很难出现请求 B 已经更新了数据库并且更新了缓存,请求 A 才更新完缓存的情况。所以推荐先更新数据库,再更新缓存

保证操作原子性

操作数据库和操作缓存其实是两个操作,前面的所有分析都是建立在这两个操作都能同时执行成功,只要出现一个执行成功,一个执行失败的情况,就会造成数据库和缓存数据不一致的问题,会对敏感业务造成影响。下面就是两种解决方案.

队列+重试机制

Redis缓存问题:穿透,击穿,雪崩,双写一致性等,缓存,redis,八股,校招,后端

  • 更新数据库数据;
  • 缓存因为种种问题删除失败
  • 将需要删除的key发送至消息队列
  • 自己消费消息,获得需要删除的key
  • 继续重试删除操作,直到成功

该方案有一个缺点,会对业务线代码造成大量的侵入。

基于订阅binlog的同步机制

Redis缓存问题:穿透,击穿,雪崩,双写一致性等,缓存,redis,八股,校招,后端

本方案启动一个订阅程序去订阅数据库的binlog,获得需要操作的数据。在应用程序中,另起一段程序,获得这个订阅程序传来的信息,进行删除缓存操作。关键是使用canal框架订阅binlog

  • 要开启mysql的binlog,需要设置binlog_format为ROW模式,并且设置server_id,保证唯一性。修改my.cnf配置文件,重启mysql服务。
[mysqld]
log-bin=mysql-bin # 开启 binlog
binlog-format=ROW # 选择 ROW 模式
server_id=1 # 配置 MySQL replaction 需要定义,不要和 canal 的 slaveId 重复
  • 查看是否修改 Binlog 成功。
# 查看 binlog 日志是否开启
show variables like 'log_%';
  • MySQL 执行 SQL 语句创建 canal 单独使用的账号,用来进行 Binlog 的同步和监听
CREATE USER canal IDENTIFIED BY 'canal';  
GRANT SELECT, REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'canal'@'%';
FLUSH PRIVILEGES;
Reference:
  1. 缓存更新的套路
  2. Java全栈知识体系

欢迎访问我的个人博客www.levitategu.cn文章来源地址https://www.toymoban.com/news/detail-860140.html

到了这里,关于Redis缓存问题:穿透,击穿,雪崩,双写一致性等的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Redis_缓存3_缓存异常(数据不一致、雪崩、击穿、穿透)

    四个方面 缓存中数据和数据库不一致 缓存雪崩 缓存击穿 缓存穿透 14.6.1数据不一致: 一致性包括两种情况 缓存中有数据,需要和数据库值相同 缓存中没有数据,数据库中的数据是最新值 如果不符合以上两种情况,则出现数据不一致的问题。 读写缓存 同步直写 异步写回

    2024年02月13日
    浏览(42)
  • Redis 原理缓存过期、一致性hash、雪崩、穿透、并发、布隆、缓存更新策略、缓存数据库一致性

    redis的过期策略可以通过配置文件进行配置 redis会把设置了过期时间的key放在单独的字典中,定时遍历来删除到期的key。 1).每100ms从过期字典中 随机挑选20个,把其中过期的key删除; 2).如果过期的key占比超过1/4,重复步骤1 为了保证不会循环过度,导致卡顿,扫描时间上限

    2024年02月08日
    浏览(58)
  • Redis缓存(双写一致性问题)

    前言 : 什么是缓存? 缓存就像自行车,越野车的避震器 举个例子:越野车,山地自行车,都拥有\\\"避震器\\\", 防止 车体加速后因惯性,在酷似\\\"U\\\"字母的地形上飞跃,硬着陆导致的 损害 ,像个弹簧一样; 同样,实际开发中,系统也需要\\\"避震器\\\",防止过高的数据访问猛冲系统,导致其操作线程无法

    2024年02月02日
    浏览(64)
  • Redis - 三大缓存问题(穿透、击穿、雪崩)

    概念: 查询一个数据库中也不存在的数据,数据库查询不到数据也就不会写入缓存,就会导致一直查询数据库 解决方法: 如果数据库也查询不到,就把空结果进行缓存 缺点是 - 消耗内存 布隆过滤器的作用 :检索一个元素是否在某个集合中 布隆过滤器由组成 : 位图 + 若干

    2024年02月14日
    浏览(40)
  • [Redis]缓存穿透、缓存击穿、缓存雪崩问题及解决方法

    缓存穿透就是指在高并发的情况下大量的请求去查询一个不存在于缓存中的数据,导致这些请求都直接访问数据库,给数据库造成压力。例如:我存储在缓存中的key是数字类型(123),但是网络攻击者频繁地用字符串(abc)去获取缓存。导致永远都无法命中缓存,请求最终都

    2024年02月15日
    浏览(50)
  • Redis缓存穿透、击穿、雪崩问题及其解决方法

    缓存穿透 :缓存穿透是指客户端请求的数据在缓存中和数据库中都不存在,这样缓存永远不会生效,这些请求都会打到数据库。 常见的解决方案有两种: 缓存空对象 优点:实现简单,维护方便 缺点: 额外的内存消耗 可能造成短期的不一致 布隆过滤 优点:内存占用较少,

    2024年02月02日
    浏览(44)
  • Redis(概述、应用场景、线程模式、数据持久化、数据一致、事务、集群、哨兵、key过期策略、缓存穿透、击穿、雪崩)

    目录 Redis概述 应用场景 Redis的线程模式 数据持久化 1.Rdb(Redis DataBase) 2.Aof(Append Only File) mysql与redis保持数据一致 redis事务 主从复制(Redis集群) 哨兵模式 key过期策略 缓存穿透、击穿、雪崩 1.缓存穿透:缓存中没有,在mysql中也没有 2.缓存击穿:数据在数据库中存在,某个

    2024年01月16日
    浏览(64)
  • 【Redis(8)】Spring Boot整合Redis和Guava,解决缓存穿透、缓存击穿、缓存雪崩等缓存问题

    在缓存技术的挑战及设计方案我们介绍了使用缓存技术可能会遇到的一些问题,那么如何解决这些问题呢? 在构建缓存系统时,Spring Boot和Redis的结合提供了强大的支持,而Guava的 LoadingCache 则为缓存管理带来了便捷的解决方案。下面我将介绍如何通过整合Spring Boot、Redis和Gu

    2024年04月22日
    浏览(48)
  • Redis---缓存双写一致性

    目录 一、什么是缓存双写一致性呢?  1.1 双检加锁机制  二、数据库和缓存一致性的更新策略 2.1、先更新数据库,后更新缓存  2.2 、先更新缓存,后更新数据库  2.3、先删除缓存,在更新数据库 延时双删的策略:  2.4.先更新数据库,在删除缓存(常用) 2.5、实际中是不可

    2024年02月15日
    浏览(49)
  • Redis缓存双写一致性

    如果redis中有数据:需要和数据库中的值相同 如果redis中无数据:数据库中的值要是最新值,且准备回写redis 缓存按照操作来分,可细分为两种: 只读缓存和读写缓存 只读缓存很简单:就是Redis只做查询,有就是有,没有就是没有,不会再进一步访问MySQL,不再需要会写机制

    2023年04月17日
    浏览(46)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包