0、前言
? ? ? ? 近期學(xué)習(xí)redis相關(guān)原理,記錄一下開發(fā)過程中Redis的一些常見問題及應(yīng)對方法。
1、緩存穿透
一句話總結(jié):先查redis發(fā)現(xiàn)沒數(shù)據(jù),再去數(shù)據(jù)庫查發(fā)現(xiàn)還是沒數(shù)據(jù)。
這種情況下緩存永遠(yuǎn)不會生效,數(shù)據(jù)庫將承擔(dān)巨大壓力。
? ? ? ? 我們知道,redis的緩存作用,是在客戶端發(fā)起查詢請求時(shí):
? ? ? ? (1)先找redis,如果redis內(nèi)命中數(shù)據(jù)則直接返回。
? ? ? ? (2)如果未命中,則不得不去數(shù)據(jù)庫中查詢,把數(shù)據(jù)放到redis里,然后再返回?cái)?shù)據(jù)給客戶端。
? ? ? ? 對于緩存穿透的情況,例如多次惡意查詢數(shù)據(jù)庫和redis里都沒有的數(shù)據(jù),將給數(shù)據(jù)庫帶來巨大壓力。
常見解決方法:
? ? ? ? ?緩存空對象,就是發(fā)現(xiàn)數(shù)據(jù)庫也沒有這個(gè)數(shù)據(jù)的時(shí)候,緩存一個(gè)空值在redis里,那么下次這種訪問就會從redis里返回null,而不會繼續(xù)查詢數(shù)據(jù)庫了。
2. 緩存雪崩
一句話:大量的緩存key同時(shí)失效(比如同時(shí)過期了),或者redis服務(wù)宕機(jī)(redis寄了),導(dǎo)致大量請求直接給到數(shù)據(jù)庫,壓力過大寄了。
????????緩存雪崩,指的是大面積的 key 同時(shí)過期,導(dǎo)致大量并發(fā)打到我們的數(shù)據(jù)庫。不像擊穿,只是因?yàn)?1 個(gè) key 的過期。所以,對于雪崩來說,一般少量的 key 失效,所帶來的數(shù)據(jù)庫的并發(fā)壓力是不會太大的。而大量 key 的同時(shí)失效,導(dǎo)致所有 key 的并發(fā)加起來,會影響到我們的數(shù)據(jù)庫。
????????那就算一個(gè) key 失效,也會對數(shù)據(jù)庫造成很大的影響,那么你把雪崩的所有 key 拆成一個(gè)一個(gè) key 來看,也就是雪崩可以拆分成一個(gè)一個(gè)緩存擊穿的集合。
????????其實(shí)在真實(shí)場景中,雪崩才是一個(gè)更容易發(fā)生的一個(gè)問題,它不像擊穿那么極端,一個(gè) key 就成千上萬的并發(fā),直接把數(shù)據(jù)庫打垮了;而是,可能就一個(gè) key 幾十幾百的并發(fā),然后大量的 key 一過期,然后就使得好多并發(fā),同時(shí)疊加起來,累積到上千上萬個(gè),把數(shù)據(jù)庫打崩了。
解決方案
? ? ? ? 怕key同時(shí)失效,那就把緩存的TTL時(shí)間分散開,?比如在失效時(shí)間的基礎(chǔ)上加上一個(gè)隨機(jī)值。
? ? ? ? 針對redis宕機(jī)情況,可以進(jìn)行Redis集群的布置,或者添加多級緩存,增強(qiáng)系統(tǒng)的容錯(cuò)性。
3、緩存擊穿
????????概括:要查的key對應(yīng)的數(shù)據(jù)是存在的(不像穿透,是不存在的數(shù)據(jù)),但redis里沒有(比如過期了,這很常見),如果這個(gè)key的數(shù)據(jù)是熱點(diǎn)數(shù)據(jù),即可能會有大量并發(fā)請求。
? ? ? ? 這么多的并發(fā)請求都發(fā)現(xiàn)redis沒有對應(yīng)的數(shù)據(jù),則都要去查數(shù)據(jù)庫,這樣一來將造成巨大壓力。
?????????例如下圖中,在線程1把數(shù)據(jù)寫入緩存之前,其他多個(gè)并發(fā)線程都會去查數(shù)據(jù)庫,這樣將造成巨大的壓力。
?解決方案
? ? ? ? 有的人可能會覺得,熱點(diǎn)key過期容易導(dǎo)致緩存擊穿,那我們把它的存活時(shí)間設(shè)成永久不就好了?
? ? ? ? 這樣肯定是不可以的,畢竟redis空間有限,不可能緩存那么多數(shù)據(jù),而且“熱點(diǎn)數(shù)據(jù)”也是會隨時(shí)間變化的,也不可能把所有數(shù)據(jù)當(dāng)成熱點(diǎn)數(shù)據(jù)來緩存。
方案1:互斥鎖(開發(fā)常用)
? ? ? ??假設(shè)會有 1w 個(gè)并發(fā)來訪問這個(gè) key,那么它們就會先查詢 redis,然后都發(fā)現(xiàn),這個(gè) key 不存在;然后,它們就會對應(yīng)的,往 redis 用 setnx 設(shè)置一個(gè) key,來表示這是一把鎖;
? ? ? ? 這里介紹一下redis的setnx,該方法的作用可以標(biāo)識鎖,什么意思呢?
? ? ? ? setnx的使用方法是這樣的:
? ? ? ? setnx key value? ? ? ? 如果key沒有value,設(shè)置值成果。如果key已經(jīng)有對應(yīng)value,設(shè)置失敗。
? ? ? ? 類似于我們的互斥。上鎖就是賦值、釋放鎖就是刪掉鎖(del key即可)
? ? ? ? 一般會設(shè)置有效期,防止死鎖。
? ? ? ? 該方法通過傳入鎖的id,返回一個(gè)布爾值,來模擬獲取鎖的過程。
????????然后,只有一個(gè)線程,會設(shè)置成功,然后去讀取數(shù)據(jù)庫,寫回 redis;其他的 9999 個(gè)線程,則 sleep 一小會,然后再去訪問我們的 redis。
????????有人看到這,首先會問,這個(gè) sleep 要多久?
????????這個(gè)是要根據(jù)壓測,以及線上環(huán)境進(jìn)行調(diào)整的,一般會給出一個(gè)合適的值,也就是大約從數(shù)據(jù)庫取出數(shù)據(jù)的時(shí)間。
?文章來源地址http://www.zghlxwxcb.cn/news/detail-464349.html
?
?方案2:邏輯過期
? ? ? ? 這種情況,我們假設(shè)key不會過期,而是通過人為地設(shè)置”expire time“一個(gè)屬性,來進(jìn)行人為地判斷數(shù)據(jù)是否過期(比如,熱門商品,那就在活動(dòng)期間把它變?yōu)椴粫^期地key,等活動(dòng)過了以后在主動(dòng)讓他過期)。
? ? ? ? 中心思路就是,線程1搶到鎖以后,將查數(shù)據(jù)庫、返回緩存,這項(xiàng)比較耗時(shí)的任務(wù)交給別的線程(線程2)去做,然后多個(gè)并發(fā)線程就可以先返回過期的數(shù)據(jù),等更新好了再返回新的。
????????這樣避免了大量線程休眠等待的情況。
文章來源:http://www.zghlxwxcb.cn/news/detail-464349.html
?
到了這里,關(guān)于Redis:緩存擊穿、緩存穿透與緩存雪崩的區(qū)別、解決方案的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!