天天看點

redis-緩存擊穿和緩存穿透

文章目錄

    • 緩存穿透
      • 定義
      • 解決政策
    • 布隆過濾器
      • 布隆過濾器原理
      • 布隆過濾器優缺點
      • 增加布隆過濾器之後的模型
      • 布隆過濾器的使用場景
    • 緩存擊穿
      • 解決方案
    • 總結

緩存穿透

定義

有很多使用者,請求接口。

為了防止mysql壓力過大,在通路量很大且資料變動不頻繁的情況下,我們通過增加redis緩存減少mysql的壓力。

正常的流程為下圖所示。

redis-緩存擊穿和緩存穿透
public function redisDemo()
    {
        $key = $_POST['key'];
        //從redis擷取資料
        $redisServer = new Redis();
        $redisInfo = $redisServer->connect('127.0.0.1','6379');
        if($redisInfo == NULL){
            throw new ErrorException("redis connect error");
        }

        $redisValueInfo = $redisServer->get($key);

        if(!empty($redisValueInfo)){
            echo "redis 中有資料,可以直接傳回";
            return $redisValueInfo;
        }

        //redis中無資料,從mysql中查找
        $mysqlServer = mysqli_connect('127.0.0.1','user','123');
        $select_db = mysqli_select_db($mysqlServer,'test');
        if (empty($select_db)) {
            echo "mysql異常";
            throw new ErrorException("redis connect error");
        }

        //查詢代碼
        $sql = "select * from db_test WHERE `id` = ".$key." limit 1";
        $mysqlRes = mysqli_query($mysqlServer,$sql);
        while ($row = mysqli_fetch_row($mysqlRes)) {
            $res[] = $row;
        }

        if(empty($res)){
            echo "mysql資料為空";
            return "nil";
        }else{
            //如果mysql查到資料,放入緩存并增加過期時間
            $redisServer->set($key,json_encode($res));
            $redisServer->expire($key,100);
        }
        return "nil";
    }
           

那麼如上的流程,存在一種情況,redis中沒有資料,資料庫也沒有此資料,最後會傳回nil。

但是每次通路都會請求redis也會請求mysql。

這樣子相當于這條請求穿透了redis也穿透了mysql。

當這種請求數目多的時候,對mysql伺服器壓力很大,很有可能導緻服務崩潰。

這就是緩存穿透。

解決政策

當然,有人可能會想到解決政策,如果mysql中沒有,我們就在redis中增加過濾政策。

那麼會出現兩種情況。

如果key未設定緩存過期時間,則redis的占用會越來越大。

如果key設定了過期時間,好處是會過濾其中一部分請求,但是redis也會增長,mysql依然會面臨一定壓力的通路。

我們可以在redis後增加一層強有力的過濾。

布隆過濾器。

布隆過濾器

那麼,為什麼用布隆過濾器好,并且,為什麼要用布隆過濾器呢?

這裡簡單說明介紹一下布隆過濾器,之後會在部落格中詳細介紹。

布隆過濾器是一個叫“布隆”的人提出的,它本身是一個很長的二進制向量,既然是二進制的向量,那麼顯而易見的,存放的不是0,就是1。參見位圖。

布隆過濾器原理

比如我們需要向布隆過濾器添加幾個數字,1,2,3,4,5布隆過濾器長度為8。

初始每個位都是0。

redis-緩存擊穿和緩存穿透

1,2,3,4,5經過hash分别對應位置1。

redis-緩存擊穿和緩存穿透

但是有一個問題,如果這些格子裡面放置的都是1,不一定代表給定的資料一定重複,也許其他資料經過三種固定的計算方式算出來的結果也是相同的。這也很好了解吧,比如我們需要判斷對象是否相等,是不可以僅僅判斷他們的哈希值是否相等的。

也就是說布隆過濾器隻能判斷資料是否一定不存在,而無法判斷資料是否一定存在。

布隆過濾器優缺點

優點:由于存放的不是完整的資料,是以占用的記憶體很少,而且新增,查詢速度夠快;

缺點: 随着資料的增加,誤判率随之增加;無法做到删除資料;隻能判斷資料是否一定不存在,而無法判斷資料是否一定存在。

增加布隆過濾器之後的模型

redis-緩存擊穿和緩存穿透

布隆過濾器的使用場景

  • 在爬蟲系統中,我們需要對 URL 進行去重,已經爬過的網頁就可以不用爬了。但是 URL 太多了,幾千萬幾個億,如果用一個集合裝下這些URL 位址那是非常浪費空間的。這時候就可以考慮使用布隆過濾器。它可以大幅降低去重存儲消耗,隻不過也會使得爬蟲系統錯過少量的頁面。
  • 郵箱系統的垃圾郵件過濾功能也普遍用到了布隆過濾器,因為用了這個過濾器,是以平時也會遇到某些正常的郵件被放進了垃圾郵件目錄中,這個就是誤判所緻,機率很低。
  • 推薦系統,已經推薦過的不在進行推薦。

緩存擊穿

上述就是緩存穿透現象,現在說一下緩存擊穿現象。

緩存擊穿是因為請求的資料不在mysql中,緩存擊穿相比于緩存穿透要簡單一些,緩存擊穿為redis鍵值失效或者redis伺服器出現異常,請求直接打在資料庫上。

這些資料在mysql上是有的,是以并不會出現穿透的現象,但是同樣會給redis很大的壓力。

這時候,布隆過濾器已經沒有作用了,因為資料是有的不能過濾掉。

此時的邏輯

redis-緩存擊穿和緩存穿透

解決方案

如果是緩存失效的問題,可以根據業務具體判斷是否不設定失效時間。

如果是redis伺服器的問題,我們可以增加一些有利的防護。

1.redis哨兵,redis cluster避免全盤崩潰。

2.在結束後可以利用redis RDB和AOF去進行恢複資料。

總結

緩存有利有弊,需要根據業務形态以及結合自身考慮去使用。

請再努力一些。

–2020.5.20晚。