Redis的緩存機(jī)制用法及說(shuō)明
Redis緩存介紹
在高并發(fā)的場(chǎng)景下,直接使用傳統(tǒng)的面向內(nèi)存的數(shù)據(jù)庫(kù),資源開(kāi)銷會(huì)非常大,性能也非常低,數(shù)據(jù)庫(kù)服務(wù)器很容易崩潰。因此可以把一些經(jīng)常用到的數(shù)據(jù)(熱數(shù)據(jù):使用頻率很高,但是占總數(shù)據(jù)量較少)統(tǒng)一放到Redis中,當(dāng)客戶端查詢時(shí),先查詢Redis,查詢不到,再去查詢數(shù)據(jù)庫(kù)。
這便是Redis緩存,它就像一個(gè)保護(hù)罩,為數(shù)據(jù)庫(kù)抵達(dá)掉了大部分請(qǐng)求:

那么問(wèn)題就來(lái)了:
- 我們?cè)趺粗滥切?shù)據(jù)是熱數(shù)據(jù)?
- 怎么保證Redis中存儲(chǔ)的一直都是熱數(shù)據(jù)?
以上便是我們接下來(lái)要討論的問(wèn)題。
緩存策略
1)定期生成
每個(gè)一定的周期,對(duì)于訪問(wèn)數(shù)據(jù)庫(kù)數(shù)據(jù)的頻率進(jìn)行統(tǒng)計(jì),選出前N%的數(shù)據(jù),放到Redis緩存中。
這種方式操作最簡(jiǎn)單,對(duì)于數(shù)據(jù)的掌控也更加穩(wěn)定。缺點(diǎn)也很明顯,就是時(shí)效性非常低。
2)實(shí)時(shí)生成
先給緩存設(shè)定容量上限(可以通過(guò) Redis 配置?件的 maxmemory 參數(shù)設(shè)定)。
接下來(lái)按照這個(gè)流程執(zhí)行:
- 先從Redis中查詢,查到了直接返回
- 查不到從數(shù)據(jù)庫(kù)中查,返回結(jié)果的同時(shí),把這個(gè)數(shù)據(jù)寫(xiě)入Redis
當(dāng)緩存達(dá)到上線,我們根據(jù)可靠的緩存淘汰策略,刪除Redis中相對(duì)不那么“熱”的數(shù)據(jù)。以此達(dá)到熱數(shù)據(jù)的動(dòng)態(tài)平衡。
3)緩存淘汰策略
包括但不限于Redis,緩存淘汰策略基本上涵蓋了以下這四點(diǎn):
- FIFO (First In First Out) 先進(jìn)先出
把緩存中存在時(shí)間最久的 (也就是先來(lái)的數(shù)據(jù)) 淘汰掉 - LRU (Least Recently Used) 淘汰最久未使用的
記錄每個(gè) key 的最近訪問(wèn)時(shí)間. 把最近訪問(wèn)時(shí)間最老的 key 淘汰掉 - LFU (Least Frequently Used) 淘汰訪問(wèn)次數(shù)最少的
記錄每個(gè) key 最近?段時(shí)間的訪問(wèn)次數(shù). 把訪問(wèn)次數(shù)最少的淘汰掉 - Random 隨機(jī)淘汰
從所有的 key 中抽取幸運(yùn)?淘汰掉
Redis中提供的緩存淘汰策略:
volatile-lru
當(dāng)內(nèi)存不足以容納新寫(xiě)入數(shù)據(jù)時(shí),從設(shè)置了過(guò)期時(shí)間的 key 中使用 LRU(最近最少使用)算法進(jìn)行淘汰。allkeys-lru
當(dāng)內(nèi)存不足以容納新寫(xiě)入數(shù)據(jù)時(shí),從所有 key 中使用 LRU(最近最少使用)算法進(jìn)行淘汰。volatile-lfu
4.0 版本新增,當(dāng)內(nèi)存不足以容納新寫(xiě)入數(shù)據(jù)時(shí),在過(guò)期期的 key 中,使用 LFU 算法進(jìn)行淘汰 key。allkeys-lfu
4.0 版本新增,當(dāng)內(nèi)存不足以容納新寫(xiě)入數(shù)據(jù)時(shí),從所有 key 中使用 LFU 算法進(jìn)行淘汰。volatile-random
當(dāng)內(nèi)存不足以容納新寫(xiě)入數(shù)據(jù)時(shí),從設(shè)置了過(guò)期時(shí)間的 key 中,隨機(jī)淘汰數(shù)據(jù)。allkeys-random
當(dāng)內(nèi)存不足以容納新寫(xiě)入數(shù)據(jù)時(shí),從所有 key 中隨機(jī)淘汰數(shù)據(jù)。volatile-ttl
在設(shè)置了過(guò)期時(shí)間的 key 中,根據(jù)過(guò)期時(shí)間的剩余大小,提前淘汰剩余時(shí)間最短的 key(相當(dāng)于 FIFO,只要過(guò)期最早的 key)。noeviction
默認(rèn)策略,當(dāng)內(nèi)存不足以容納新寫(xiě)入數(shù)據(jù)時(shí),新寫(xiě)入操作會(huì)報(bào)錯(cuò)。
Redis中的緩存淘汰策略也都是圍繞LCU,LFU來(lái)進(jìn)行的,只不過(guò)分為allkeys(全部數(shù)據(jù))和volatile(設(shè)置過(guò)期時(shí)間的數(shù)據(jù))
緩存中需要考慮的問(wèn)題
1)緩存預(yù)熱
試想以下,加入Redis剛啟動(dòng),里面還沒(méi)有任何數(shù)據(jù)寫(xiě)入,那么發(fā)過(guò)來(lái)的請(qǐng)求,直接就進(jìn)入到了數(shù)據(jù)庫(kù)中,數(shù)據(jù)庫(kù)仍然會(huì)面臨很大的壓力。
解決辦法很簡(jiǎn)單,就是按照定期生成熱數(shù)據(jù)的方式,把熱數(shù)據(jù)先寫(xiě)入Redsi。即使時(shí)效性不高,能為數(shù)據(jù)庫(kù)(如MySQL)抵擋大部分請(qǐng)求就可以。
2)緩存穿透 (Cache penetration)
定義:
- 由于發(fā)送過(guò)來(lái)的key是無(wú)效的。
- 數(shù)據(jù)庫(kù)和Redis緩存中肯定都沒(méi)有,頻繁的這種無(wú)效key請(qǐng)求,一定會(huì)壓垮數(shù)據(jù)庫(kù)。
產(chǎn)生原因:
- 業(yè)務(wù)代碼出現(xiàn)漏洞,對(duì)參數(shù)的校驗(yàn)出了問(wèn)題
- 開(kāi)發(fā)/運(yùn)維不小心刪除了某個(gè)熱數(shù)據(jù)key,自己卻沒(méi)有發(fā)現(xiàn)
- 黑客惡意攻擊
解決辦法:
- 針對(duì)數(shù)據(jù)庫(kù)查詢的參數(shù)進(jìn)行嚴(yán)格校驗(yàn),避免無(wú)效key請(qǐng)求
- 對(duì)于數(shù)據(jù)庫(kù)中不存在的key,在Redis緩存中設(shè)置一個(gè)""值,直接攔截非法key請(qǐng)求
- 使用布隆過(guò)濾器,判定key是否存儲(chǔ)在,存在才進(jìn)行查詢
布隆過(guò)濾器
- 是一種高效查詢?cè)厥欠翊嬖诘臄?shù)據(jù)結(jié)構(gòu)。
- 簡(jiǎn)單的可以認(rèn)為是hash+位圖方式實(shí)現(xiàn),不存儲(chǔ)實(shí)際值,占用的內(nèi)存很少
3)緩存雪崩(Cache avalanche)
定義:
- 短時(shí)間內(nèi)大量key同時(shí)過(guò)期,導(dǎo)致數(shù)據(jù)庫(kù)查詢操作激增
出現(xiàn)原因:
- 設(shè)置key,時(shí)使用了統(tǒng)一的過(guò)期時(shí)間
解決辦法:
- 不給key添加過(guò)期時(shí)間或者添加隨機(jī)過(guò)期時(shí)間因子
4) 緩存擊穿(Cache breakdown)
定義:
- 緩存雪崩是大量key同時(shí)失效,Cache breakdown是某一個(gè)或者多個(gè)熱數(shù)據(jù)的key失效。而這些熱數(shù)據(jù)訪問(wèn)頻率很高,導(dǎo)致數(shù)據(jù)庫(kù)查詢次數(shù)激增
- 在 Redis 和緩存系統(tǒng)的語(yǔ)境下,“緩存 Breakdown”通常指 緩存擊穿。
簡(jiǎn)單來(lái)說(shuō),就是某一個(gè)熱點(diǎn) Key(比如雙 11 的秒殺商品)在過(guò)期的瞬間,同時(shí)有海量的請(qǐng)求打過(guò)來(lái)。因?yàn)榫彺媸Я?,這些請(qǐng)求會(huì)像洪流一樣直接沖向數(shù)據(jù)庫(kù),可能導(dǎo)致數(shù)據(jù)庫(kù)瞬間宕機(jī)。
處理這個(gè)問(wèn)題,核心思路只有兩個(gè):不讓請(qǐng)求全都去查數(shù)據(jù)庫(kù),或者干脆不讓熱點(diǎn) Key 過(guò)期。
1. 設(shè)置互斥鎖 (Mutex Lock)
這是最常用的方案。當(dāng)緩存失效時(shí),不是每個(gè)請(qǐng)求都去查數(shù)據(jù)庫(kù),而是先讓請(qǐng)求嘗試獲取一個(gè)“鎖”(通常用 Redis 的 SETNX 命令)。
- 原理:只有拿到鎖的那個(gè)請(qǐng)求能去數(shù)據(jù)庫(kù)查數(shù)據(jù)并回寫(xiě)緩存,其他沒(méi)拿到鎖的請(qǐng)求要么等待重試,要么返回空值。
- 優(yōu)點(diǎn):保證了數(shù)據(jù)庫(kù)的安全性,數(shù)據(jù)一致性高。
- 缺點(diǎn):代碼邏輯稍微復(fù)雜,且在高并發(fā)下會(huì)有一定的等待延遲。
2. 熱點(diǎn)數(shù)據(jù)“永不過(guò)期”
從物理上或者邏輯上讓這個(gè) Key 永遠(yuǎn)存在。
- 物理永不過(guò)期:在
SET的時(shí)候不設(shè)置過(guò)期時(shí)間。這種方式最穩(wěn),但占用內(nèi)存且無(wú)法自動(dòng)更新。 - 邏輯永不過(guò)期(后臺(tái)異步更新):給數(shù)據(jù)設(shè)置一個(gè)邏輯上的過(guò)期時(shí)間(存放在 Value 里)。
- 當(dāng)程序發(fā)現(xiàn)邏輯時(shí)間快到期時(shí),由一個(gè)后臺(tái)線程異步去數(shù)據(jù)庫(kù)更新這個(gè) Key,并延長(zhǎng)邏輯時(shí)間。
- 在更新完成前,所有請(qǐng)求繼續(xù)讀取舊的數(shù)據(jù)。
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
基于redis實(shí)現(xiàn)的點(diǎn)贊功能設(shè)計(jì)思路詳解
點(diǎn)贊是我們現(xiàn)在經(jīng)常見(jiàn)到的一個(gè)效果,如朋友圈、微博都有點(diǎn)贊的效果,下面這篇文章主要跟大家分享了基于redis實(shí)現(xiàn)的點(diǎn)贊功能設(shè)計(jì)思路的相關(guān)資料,文中介紹的非常詳細(xì),對(duì)大家實(shí)現(xiàn)點(diǎn)贊功能具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起看看吧。2017-05-05
Redis優(yōu)化經(jīng)驗(yàn)總結(jié)(必看篇)
下面小編就為大家?guī)?lái)一篇Redis優(yōu)化經(jīng)驗(yàn)總結(jié)(必看篇)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-03-03
使用Redis實(shí)現(xiàn)請(qǐng)求限制與速率限制
API速率限制(Rate Limiting)是控制用戶訪問(wèn)API的請(qǐng)求速率的一種機(jī)制,防止系統(tǒng)被過(guò)多請(qǐng)求淹沒(méi),下面我們來(lái)看看如何使用Redis和FastAPI實(shí)現(xiàn)請(qǐng)求限制與速率控制吧2025-04-04
Redis?SortedSet數(shù)據(jù)類型及其常用命令總結(jié)
Redis的SortedSet是一個(gè)可排序的set集合,與Java中的TreeSet有些類似,但底層數(shù)據(jù)結(jié)構(gòu)卻差別很大,這篇文章主要介紹了Redis?SortedSet數(shù)據(jù)類型及其常用命令詳解,需要的朋友可以參考下2024-06-06
在Redis集群中使用pipeline批量插入的實(shí)現(xiàn)方法
這篇文章主要介紹了在Redis集群中使用pipeline批量插入的實(shí)現(xiàn)方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-05-05

