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

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

