redis Redis緩存穿透與雪崩解決方案

起因:隨著項目的進一步推廣,數(shù)據(jù)量的增大,直接訪問mysql數(shù)據(jù)庫獲取數(shù)據(jù)所使用的時間越來越長,為解決當前主要矛盾,決定引入redis非關(guān)系型數(shù)據(jù)庫作為緩存層,使得數(shù)據(jù)并不能直接命中數(shù)據(jù)庫,減少訪問數(shù)據(jù)庫帶來的壓力,從而加快運行速度。


1. Redis緩存穿透解決方案

1.1. 緩存穿透的場景

get傳參數(shù),參數(shù)一般是id,如果這個id是一個無效id

String key = request.getParameter("key");
List<BuyCart> list = new ArrayList();
//習(xí)慣性會用json來保存結(jié)構(gòu)數(shù)據(jù)
String cartJson = redisOperator.get(key);
if(StringUtls.isBlank(cartJson)){
  //redis里面沒有保存這個key
  list = cartService.getCarts(key);
  //從數(shù)據(jù)庫里查出來然后寫入redis
  if(list!=null&&list.size()>0){
    redisOperator.set("cartId:"+key,JsonUtils.objectToJson(list));
  }else{
    redisOperator.set("cartId:"+key,JsonUtils.objectToJson(list),10*60);
  }
}else{
  //redis里有值
  list = JsonUtils.jsonToList(list));
}

假如我系統(tǒng)被人攻擊了,如何攻擊?

get傳參數(shù),傳N個無效的id

1.2. 布隆過濾器bloomfilter

之前講了一個hyperloglog,保存不重復(fù)的基數(shù)個數(shù):比如記錄訪問的UV,我只需要個數(shù)

場景描述

比如我們一個新聞客戶端,不斷的給用戶推薦的新聞,推薦去重,還要高效

這個時候你想到Redis,能實時推送并快速去重

用戶A:1 2 3 4 5 6(2 7 9)每個用戶都應(yīng)該有一個瀏覽的歷史記錄:一旦時間長了,是不是數(shù)據(jù)量就非常大

如果用戶量也很大怎么辦?

這個時候我們的布隆過濾器就登場了

總結(jié)一下

  • 布隆過濾器可以判斷數(shù)據(jù)是否存在
  • 并且可以節(jié)省90%以上的存儲空間
  • 但匹配精度會有一點不準確(涉及空間和時間的轉(zhuǎn)換:0.01%)

1.2.1. 布隆過濾器的運行場景

它本身是一個二進制的向量,存放的就是0,1

比如我們新建一個長度為16的布隆過濾器

image-20200212211741872.png

所以布隆過濾器的精度是取決于bloom的存儲大小的的,如果長度越大,精度就越高

布隆過濾器的特征

  • 精度是取決于bloom的存儲大小的的,如果長度越大,精度就越高
  • 只能判斷數(shù)據(jù)是否一定不存在,而無法判斷數(shù)據(jù)是否一定存在
  • bloom的存儲節(jié)點不能刪除,一旦刪除就影響其他節(jié)點數(shù)據(jù)的特征了

布隆過濾器存儲的節(jié)點數(shù)據(jù)一定是歷史數(shù)據(jù)

1.2.2. 布隆過濾器的使用

到入google的guava的POM

        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>28.2-jre</version>
        </dependency>

BloomFilter的代碼測試

public class BloomFilterTest {
    public static void main(String[] args) {
            //字符集,bf的存儲長度一般是你要存放的數(shù)據(jù)量1.5-2倍,期望的誤判率
        BloomFilter bf = BloomFilter.create(Funnels.stringFunnel(Charset.forName("utf-8")),100000,0.0001);
        for(int i=0;i<100000;i++){
            bf.put(String.valueOf(i));
        }
        int flag = 0;
        for(int i=100000;i<200000;i++){
            if(bf.mightContain(String.valueOf(i))){
                flag++;
            }
        }
        System.out.println("誤判了:"+flag);

    }
}

1.2.3. Redis集成布隆過濾器

Redis官方提供的布隆過濾器支持的是到了Redis4.x以后提供的插件功能

# 下載bloomfilter的插件
wget https://github.com/RedisLabsModules/rebloom/archive/v1.1.1.tar.gz
# 解壓
make
# 去到redis的配置文件對我們的過濾器進行添加
loadmodule /usr/local/software/RedisBloom-1.1.1/rebloom.so
# 創(chuàng)建bloomfilter并添加一個值
# 默認過濾器長度為100,精度0.01 : MBbloom
bf.add users value1 #可以不斷添加到同一個key
bf.madd users value1 value2
# 判斷一個值是否存在
bf.exists users value1
# 判斷多個值是否存在
bf.mexists users value1 value2 value3
# 手工建立bloomfliter的配置
bf.reserve userBM 0.001 10000

1.2.4. Java集成Redis BloomFilter

先導(dǎo)入依賴

<dependency>
  <groupId>com.redislabs</groupId>
  <artifactId>jrebloom</artifactId>
  <version>1.2.0</version>
</dependency>

Java的bloomfilter調(diào)用

import io.rebloom.client.Client;

public class RedisBloomFilterTest {
    public static void main(String[] args) {
        Client bloomClient = new Client("127.0.0.1",6379);
        //先創(chuàng)建bloomfilter
        bloomClient.createFilter("userFilter",1000,0.001);
        bloomClient.add("userFilter","gavin");
        System.out.println("bloomfilter:"+bloomClient.exists("userFilter","gavin"));
    }
}

1.2.5. 布隆過濾器的使用總結(jié)

  • 布隆過濾器如果初始值過大會占用較大空間,過小會誤差率高,使用前估計好元素數(shù)量
  • error_rate越小,占用空間就越大
  • 只能判斷數(shù)據(jù)是否一定不存在,而無法判斷數(shù)據(jù)是否一定存在
  • 可以節(jié)省90%的存儲空間
  • 但匹配精度會有一點不準確(涉及空間和時間的轉(zhuǎn)換:0.01%)
  • 布隆過濾器只能add和exists不能delete
help @generic

2. Redis雪崩解決方案

2.1. 什么是Redis雪崩

  • 雪崩是基于數(shù)據(jù)庫,所有原理應(yīng)該到Redis的查詢?nèi)紻B,并且是同時到達

  • 緩存在同一時間大量的key過期(key)

  • 多個用戶同時請求并到達數(shù)據(jù),而且這個請求只有一個是有意義的,其他的都是重復(fù)無用功

2.2. Redis雪崩解決方案

  • 緩存用不過期:冰封了
  • 過期時間錯開(可以在key創(chuàng)建時加入一個1-10分鐘的隨機數(shù)給到key)
  • 多緩存數(shù)據(jù)結(jié)合(不要直接打到DB上,可以在DB上再加一個搜索引擎)
  • 在代碼里通過鎖解決(synchronized,分布式鎖zookeeper)

不要以為每天把功能完成了就行了,這種思想是要不得的,互勉~!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容