天天看點

Redis應用之緩存實作

文章目錄

   Redis緩存

       1.緩存概述

       2.緩存方式

           2.1不設定過期時間

           2.2設定過期時間

       3.名稱解釋

           緩存穿透

           緩存雪崩

           緩存擊穿

       4.總結

 Redis的衆多應用場景中緩存絕對是頻率最高的場景了。本文來介紹下Redis作為緩存要注意的地方。

Redis緩存

1.緩存概述

 緩存(Cache)的作用是減少伺服器對資料源的通路頻率,進而提高資料庫的穩定性。通路的流程如下。

Redis應用之緩存實作
流程圖
Redis應用之緩存實作
代碼邏輯

public Goods searchArticleById(Long goodsId){
    Object object = redisTemplate.opsForValue().get(String.valueOf(goodsId));
    if(object != null){// 緩存查詢到了結果
        return (Goods)object;
    }
    // 開始查詢資料庫
    Goods goods = goodsMapper.selectByPrimaryKey(goodsId);
    if(goods!=null){
        // 将結果儲存到緩存中
        redisTemplate.opsForValue().set(String.valueOf(goodsId),goods,60,TimeUnit.MINUTES);;
    }
    return goods;
}      

2.緩存方式

 緩存中的資料在redis中的存儲方式有兩種,一種是永久存在,不設定過期時間,第二種是設定過期時間。這兩種方式都需要盡可能的保證資料的一緻性(和資料源中的資料保持同步)。

2.1不設定過期時間

 當我們将緩存資料的key設定為永久存在時會存在資料同步和記憶體消耗逐漸增大的情況,解決方式如下:

資料同步:

   禁止直接操作資料源,避免因資料源直接被改動而造成緩存資料不一緻的問題

   如果有其他系統操作同一個資料源,這種情況肯定會産生資料不一緻的情況。

   系統執行DML操作時,應該将緩存中對應的資料删除。使用者下一次相關請求時直接從資料源中擷取。

記憶體消耗:

 随着業務的增多,緩存資料必然會越來越多,所占用的記憶體也随之增多,系統的壓力也會變大,這時一種方式是給key設定過期時間,但是過期時間長短不太好把握,這時我們可以通過設定redis最大記憶體來實作,并讓Redis按照一定的規則淘汰不需要的緩存鍵,這種方式在redis隻作為緩存使用時非常實用。

具體實作方式:修改redis配置檔案(redis.conf)中的maxmemory參數既可,限制Redis最大可用記憶體大小(機關位元組),當超出了這個限制時Redis會依據maxmemory-policy參數指定的政策來删除不需要的key直到Redis占用的記憶體小于指定記憶體。

Redis應用之緩存實作
Redis應用之緩存實作

LRU:(Least recently used,最近最少使用)算法根據資料的曆史通路記錄來進行淘汰資料,其核心思想是“如果資料最近被通路過,那麼将來被通路的幾率也更高”

LFU:(Least Frequently Used)算法根據資料的曆史通路頻率來淘汰資料,其核心思想是“如果資料過去被通路多次,那麼将來被通路的頻率也更高”。

2.2設定過期時間

 對儲存到Redis中的key設定過期時間,但同樣也會遇到問題,比如過期時間怎麼設定,記憶體資源同樣也會過大。

記憶體資源

 同樣需要設定maxmemory來限制redis使用的最大記憶體和配置maxmemory-policy來指定删除政策。

過期時間設定

 過期時間不要設定統一固定的時間,比如60分鐘,這樣會造成相同時間點大量緩存被清空,資料庫通路量突然增大的情況,我們應該對過期時間設定合理範圍内的随機值。比如:采取不同分類商品,緩存不同周期。在同一分類中的商品,加上一個随機因子。這樣能盡可能分散緩存過期時間,而且,熱門類目(女裝)的商品緩存時間長一些,冷門類目(圖書)的商品緩存時間短一些,也能節省緩存服務的資源。

public Goods searchArticleById(Long goodsId){
    Object object = redisTemplate.opsForValue().get(String.valueOf(goodsId));
    if(object != null){// 緩存查詢到了結果
        return (Goods)object;
    }
    // 開始查詢資料庫
    Goods goods = goodsMapper.selectByPrimaryKey(goodsId);
    if(goods!=null){
        Random random = new Random();
        // 将結果儲存到緩存中
        if(goods.getGoodsCategory().equals("女裝")){
            int time = 3600 + random.nextInt(3600);
            // 熱門商品
            redisTemplate.opsForValue()
                        .set(String.valueOf(goodsId)
                            ,goods
                            ,time
                            ,TimeUnit.MINUTES);
        }else{
            int time = 600 + random.nextInt(600);
            // 冷門商品
            redisTemplate.opsForValue()
                        .set(String.valueOf(goodsId)
                            ,goods
                            ,time
                            ,TimeUnit.MINUTES);
        }
    }else{
        // 防止緩存穿透
        redisTemplate.opsForValue()
                        .set(String.valueOf(goodsId)
                            ,null
                            ,60
                            ,TimeUnit.MINUTES);
    }
    return goods;
}      

3.名稱解釋

緩存穿透

 緩存穿透,是指查詢一個資料庫一定不存在的資料。正常的使用緩存流程大緻是,資料查詢先進行緩存查詢,如果key不存在或者key已經過期,再對資料庫進行查詢,并把查詢到的對象,放進緩存。如果資料庫查詢對象為空,則不放進緩存。

public Goods searchArticleById(Long goodsId){
    Object object = redisTemplate.opsForValue().get(String.valueOf(goodsId));
    if(object != null){// 緩存查詢到了結果
        return (Goods)object;
    }
    // 開始查詢資料庫
    Goods goods = goodsMapper.selectByPrimaryKey(goodsId);
    if(goods!=null){
        // 将結果儲存到緩存中
        redisTemplate.opsForValue().set(String.valueOf(goodsId),goods,60,TimeUnit.MINUTES);
    }else{
redisTemplate.opsForValue().set(String.valueOf(goodsId),null,60,TimeUnit.SECONDS);
    }
    return goods;
}      

 采用緩存空值的方式,如果從資料庫查詢的對象為空,也放入緩存,隻是設定的緩存過期時間較短,比如設定為60秒。

緩存雪崩

 緩存雪崩,是指在某一個時間段,緩存集中過期失效.解決方式就是上面設定過期時間中使用的方式,靈活設定過期時間。

緩存擊穿

 緩存擊穿,是指一個key非常熱點,在不停的扛着大并發,大并發集中對這一個點進行通路,當這個key在失效的瞬間,持續的大并發就穿破緩存,直接請求資料庫,就像在一個屏障上鑿開了一個洞。解決方式直接設定為永久key就可以了。mutex key互斥鎖可以學習下,但一般情況下用不上!

4.總結

 搞清楚了緩存的這些知識點我們選擇就比較清楚了,具體的靈活使用。

   設定Redis最大使用記憶體是必須的。

   通過不同的政策設定過期時間。

   如果是熱點key我們可以直接設定為永久key。