缓存穿透,击穿,雪崩

转载

帮你解读什么是Redis缓存穿透、缓存击穿和缓存雪崩(包含解决方案)

前言

作为一种非关系型数据库,redis也总是免不了有各种各样的问题,这篇文章主要是针对其中三个问题进行讲解:缓存穿透、缓存击穿和缓存雪崩,并给出一些解决方案。

一、缓存穿透

1、概念

缓存穿透是指查询一个数据库一定不存在的数据。正常的使用缓存流程大致是,数据查询先进行缓存查询,如果key不存在或者key已经过期,再对数据库进行查询,并把查询到的对象,放进缓存。如果数据库查询对象为空,则不放进缓存。

这里需要注意缓存击穿的区别,缓存击穿,缓存击穿是指缓存中没有但数据库中有的数据,并且某一个key非常热点,在不停的扛着大并发,大并发集中对这一个点进行访问,当这个key在失效的瞬间(一般是缓存时间到期),持续的大并发就穿破缓存,直接请求数据库,就像在一个屏障上凿开了一个洞。

为了避免缓存穿透其实有很多种解决方案。下面介绍几种

2、解决方案

(1)布隆过滤器

布隆过滤器是一个bit向量或者bit,如果我们要映射一个值到布隆过滤器中,我们使用多个不同的哈希函数生成多个哈希值,并将每个生成的哈希值指向的bit位设置为1,如下baidu一词设置了三个位置为1。

原理:对一个key进行k个hash算法获取k个值,在比特数组中将这k个值散列后设定为1,然后查的时候如果特定的这几个位置都为1,那么布隆过滤器判断该key存在。

image

“tencent”一词,对应的情况

image

可以看到,不同的词对应的bit位置可能相同,当词很多的情况时,可能大部分bit位置都是1,这时查询taobao可能对应的位置都为1,只能说明taobao一词可能存在,不是一定存在的,这时1就被覆盖了,这就是布隆过滤器的误判。如果它说不存在那肯定不存在,如果它说存在,那数据有可能实际不存在。

Redis的bitmap只支持2^32大小,对应到内存也就是512MB,误判率万分之一,可以放下2亿左右的数据,性能高,空间占用率及小,省去了大量无效的数据库连接。

因此我们可以通过布隆过滤器,将Redis缓存穿透控制在一个可容范围内。

image

使用布隆过滤器:
导入依赖

<dependency>
     <groupId>com.google.guava</groupId>
     <artifactId>guava</artifactId>
     <version>19.0</version>
</dependency>

代码:

public class Test {

    private static int size = 1000000;//预计要插入多少数据

    private static double fpp = 0.01;//期望的误判率

    private static BloomFilter<Integer> bloomFilter = BloomFilter.create(Funnels.integerFunnel(), size, fpp);

    public static void main(String[] args) {
        //插入数据
        for (int i = 0; i < 1000000; i++) {
            bloomFilter.put(i);
        }
        int count = 0;
        for (int i = 1000000; i < 2000000; i++) {
            if (bloomFilter.mightContain(i)) {
                count++;
                System.out.println(i + "误判了");
            }
        }
        System.out.println("总共的误判数:" + count);
    }
}

应用:

@Cacheable(value="key1")
public String get(String key) {
    String value = redis.get(key);  
    // redis中不存在该缓存
    if (value  == null) {
    //布隆过滤器也没有,直接返回
        if(!bloomfilter.mightContain(key)){
            return null; 
        }else{
            //布隆过滤器中能查到,不代表一定有,查出来放入redis,同样也可以避免缓存穿透
            value = db.get(key);
            redis.set(key, value); 
        }    
    }
    return value;
}

(2)、缓存空对象
当存储层不命中后,即使返回的空对象也将其缓存起来,同时会设置一个过期时间,之后再访问这个数据将会从缓存中获取,保护了后端数据源。

image

但是这种方法会存在两个问题:

● 如果空值能够被缓存起来,这就意味着缓存需要更多的空间存储更多的键,因为这当中可能会有很多的空值的键;

● 即使对空值设置了过期时间,还是会存在缓存层和存储层的数据会有一段时间窗口的不一致,这对于需要保持一致性的业务会有影响。

二、缓存雪崩

(1)、概念
缓存雪崩是指缓存中大批量数据到过期时间,而查询数据量巨大,引起数据库压力过大甚至down机。和缓存击穿不同的是,缓存击穿指并发查同一条数据,缓存雪崩是不同数据都过期了,很多数据都查不到从而查数据库。

image

产生雪崩的原因之一,假如马上就要到双十一零点,很快就会迎来一波抢购,这波商品时间比较集中的放入了缓存,假设缓存一个小时。那么到了凌晨一点钟的时候,这批商品的缓存就都过期了。而对这批商品的访问查询,都落到了数据库上,对于数据库而言,就会产生周期性的压力波峰。

博主在做电商项目的时候,一般有三种方法:
(1)采取不同分类商品,缓存不同周期。在同一分类中的商品,加上一个随机因子。这样能尽可能分散缓存过期时间,而且,热门类目的商品缓存时间长一些,冷门类目的商品缓存时间短一些,也能节省缓存服务的资源。
(2)如果缓存数据库是分布式部署,将 热点数据均匀分布在不同的缓存数据库中。
(3)设置热点数据永远不过期。

![image](https://upload-images.jianshu.io/upload_images/4093303-3d071e7106f66bcc.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

(4) 使用加锁限流的方式

![image](https://upload-images.jianshu.io/upload_images/4093303-45a91c40b84465e1.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) ![image](https://upload-images.jianshu.io/upload_images/4093303-1c49f13e74c0aebc.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) ![image](https://upload-images.jianshu.io/upload_images/4093303-7f2ba19bfe21f840.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

三、缓存击穿

(1)概念
缓存击穿,是指缓存中没有但数据库中有的数据,并且某一个key非常热点,在不停的扛着大并发,大并发集中对这一个点进行访问,当这个key在失效的瞬间(一般是缓存时间到期),持续的大并发就穿破缓存,直接请求数据库,就像在一个屏障上凿开了一个洞。

(2)解决方案

设置热点数据永远不过期。

使用互斥锁(mutex key)
业界比较常用的做法,是使用mutex。简单地来说,就是在缓存失效的时候(判断拿出来的值为空),不是立即去load db,而是先使用缓存工具的某些带成功操作返回值的操作(比如Redis的SETNX或者Memcache的ADD)去set一个mutex key,当操作返回成功时,再进行load db的操作并回设缓存;否则,就重试整个get缓存的方法。

SETNX,是「SET if Not eXists」的缩写,也就是只有不存在的时候才设置,可以利用它来实现锁的效果。

public String get(key) {
      String value = redis.get(key);
      if (value == null) { //代表缓存值过期
          //设置3min的超时,防止del操作失败的时候,下次缓存过期一直不能load db
            if (redis.setnx(key_mutex, 1, 3 * 60) == 1) {  //代表设置成功
               value = db.get(key);
               redis.set(key, value, expire_secs);
               redis.del(key_mutex);
          } else {  //这个时候代表同时候的其他线程已经load db并回设到缓存了,这时候重试获取缓存值即可
               sleep(50);
               get(key);  //重试
              }
      } else {
          return value;      
   }
 }

来源:开源中国

作者:Java技术大联盟

原文:https://my.oschina.net/u/4606167/blog/4529573

编辑于 08-26

Java

Redis

程序员

​赞同 45 ​ ​添加评论

​分享

​喜欢 ​收藏 ​申请转载

</article>

推荐阅读

[[图片上传失败...(image-3591ac-1599527406197)]

如何解决Redis雪崩、穿透、并发等5大难题

优知学院](https://zhuanlan.zhihu.com/p/58331707)
[# 什么是Redis的雪崩、穿透和击穿?崩溃之后会怎样?系统如何应对这种情况?如何处理Redis的穿透?

面试题了解什么是 redis 的雪崩、穿透和击穿?redis 崩溃之后会怎么样?系统该如何应对这种情况?如何处理 redis 的穿透? 面试官心理分析其实这是问到缓存必问的,因为缓存雪崩和穿透,是…

蛙课网](https://zhuanlan.zhihu.com/p/82980434)
[[图片上传失败...(image-331658-1599527406197)]

Redis缓存穿透、缓存雪崩、并发问题分析与解决方案

慕容千语发表于JAVA进...](https://zhuanlan.zhihu.com/p/69683926)
[[图片上传失败...(image-77c7af-1599527406196)]

为什么我们做分布式使用 Redis ?

程序之心 ...发表于程序之心](https://zhuanlan.zhihu.com/p/50392209)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342