文章目錄
Redis緩存
1.緩存概述
2.緩存方式
2.1不設定過期時間
2.2設定過期時間
3.名稱解釋
緩存穿透
緩存雪崩
緩存擊穿
4.總結
Redis的衆多應用場景中緩存絕對是頻率最高的場景了。本文來介紹下Redis作為緩存要注意的地方。
Redis緩存
1.緩存概述
緩存(Cache)的作用是減少伺服器對資料源的通路頻率,進而提高資料庫的穩定性。通路的流程如下。
流程圖 代碼邏輯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占用的記憶體小于指定記憶體。
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。