一、緩存
1、定義
緩存就是數(shù)據(jù)交換的緩沖區(qū),緩存就是緩沖區(qū)內(nèi)的數(shù)據(jù),一般從數(shù)據(jù)庫中獲取,存儲(chǔ)于本地代碼。
由于其被Static修飾,所以隨著類的加載而被加載到內(nèi)存之中,作為本地緩存,由于其又被final修飾,所以其引用和對(duì)象之間的關(guān)系是固定的,不能改變,因此不用擔(dān)心賦值(=)導(dǎo)致緩存失效。
2、作用
緩存數(shù)據(jù)存儲(chǔ)于代碼中,而代碼運(yùn)行在內(nèi)存中,內(nèi)存的讀寫性能遠(yuǎn)高于磁盤,緩存可以大大降低用戶訪問并發(fā)量帶來的服務(wù)器讀寫壓力
二、緩存穿透
1、產(chǎn)生原因
緩存穿透指客戶端請(qǐng)求的數(shù)據(jù)在緩存中和數(shù)據(jù)庫中都不存在,這樣緩存永遠(yuǎn)不會(huì)生效,這些請(qǐng)求都會(huì)打到數(shù)據(jù)庫。先查Redis,再查數(shù)據(jù)庫。當(dāng)高度發(fā)的訪問請(qǐng)求到達(dá)時(shí),緩存穿透不僅增加了響應(yīng)時(shí)間,而且還會(huì)引發(fā)對(duì) DBMS 的高并發(fā)查詢,這種高并發(fā)查詢很可能會(huì)導(dǎo)致DBMS的崩潰。
2、解決方案
①緩存空對(duì)象
優(yōu)點(diǎn):增強(qiáng)回寫,實(shí)現(xiàn)簡(jiǎn)單,維護(hù)方便;缺點(diǎn):增加內(nèi)存消耗,數(shù)據(jù)不一致。
②布隆過濾器
優(yōu)點(diǎn):內(nèi)存占用較少,沒有多余key;缺點(diǎn):實(shí)現(xiàn)復(fù)雜,存在誤判可能。
3、緩存空對(duì)象思路
當(dāng)我們客戶端訪問不存在的數(shù)據(jù)時(shí),先請(qǐng)求redis,但是此時(shí)redis中沒有數(shù)據(jù),此時(shí)會(huì)訪問到數(shù)據(jù)庫,但是數(shù)據(jù)庫中也沒有數(shù)據(jù),這個(gè)數(shù)據(jù)穿透了緩存打到數(shù)據(jù)庫,所以即使數(shù)據(jù)庫不存在數(shù)據(jù),也要存儲(chǔ)到redis,下次訪問不存在的數(shù)據(jù)也不會(huì)去請(qǐng)求數(shù)據(jù)庫,而是請(qǐng)求redis。
4、布隆過濾器思路
布隆過濾器其實(shí)采用的是哈希思想來解決這個(gè)問題,通過一個(gè)龐大的二進(jìn)制數(shù)組,走哈希思想去判斷當(dāng)前這個(gè)要查詢的這個(gè)數(shù)據(jù)是否存在,如果布隆過濾器判斷存在,則放行,這個(gè)請(qǐng)求會(huì)去訪問redis,哪怕此時(shí)redis中的數(shù)據(jù)過期了,但是數(shù)據(jù)庫中一定存在這個(gè)數(shù)據(jù),在數(shù)據(jù)庫中查詢出來這個(gè)數(shù)據(jù)后,再將其放入到redis中,判斷不存在,則直接返回。
總結(jié)一句話:將所有的key放到布隆過濾器+redis里面,其余返回null。
三、緩存雪崩
1、產(chǎn)生原因
緩存雪崩是指在同一時(shí)段大量的緩存key同時(shí)失效或者Redis服務(wù)宕機(jī),導(dǎo)致大量請(qǐng)求到達(dá)數(shù)據(jù)庫,帶來巨大壓力。
2、解決
①redis中key設(shè)置永不過期或者過期時(shí)間不同、
②redis緩存集群實(shí)現(xiàn)高可用,即使用主從復(fù)制和哨兵機(jī)制以及開啟redis持久化aof和rdb,恢復(fù)緩存集群。
③多緩存結(jié)合預(yù)防雪崩——ehcache本機(jī)緩存+redis緩存
④服務(wù)降級(jí)——哨兵限流和降級(jí)。
四、緩存擊穿
1、產(chǎn)生原因
緩存擊穿問題也叫熱點(diǎn)Key問題,就是一個(gè)被高并發(fā)訪問并且緩存重建業(yè)務(wù)較復(fù)雜的key突然失效了,無數(shù)的請(qǐng)求訪問會(huì)在瞬間給數(shù)據(jù)庫帶來巨大的沖擊。造成某一時(shí)刻的數(shù)據(jù)庫請(qǐng)求量過大,壓力劇增。
2、解決
①差異失效時(shí)間,對(duì)于訪問頻繁的key,不設(shè)置過期時(shí)間。
②互斥鎖
多個(gè)線程同時(shí)去查詢數(shù)據(jù)庫的這條數(shù)據(jù),我們?cè)诘谝粋€(gè)查詢數(shù)據(jù)的請(qǐng)求上使用一個(gè)互斥鎖來鎖住文章來源:http://www.zghlxwxcb.cn/news/detail-496995.html
其他的線程走到這一步拿不到鎖等著。等到第一個(gè)線程查詢到數(shù)據(jù)做緩存,后面的線程進(jìn)來發(fā)現(xiàn)已經(jīng)有緩存,直接走緩存。文章來源地址http://www.zghlxwxcb.cn/news/detail-496995.html
public Shop queryWithMutex(Long id) {
String key = CACHE_SHOP_KEY + id;
// 1、從redis中查詢商鋪緩存
String shopJson = stringRedisTemplate.opsForValue().get("key");
// 2、判斷是否存在
if (StrUtil.isNotBlank(shopJson)) {
// 存在,直接返回
return JSONUtil.toBean(shopJson, Shop.class);
}
//判斷命中的值是否是空值
if (shopJson != null) {
//返回一個(gè)錯(cuò)誤信息
return null;
}
// 4.實(shí)現(xiàn)緩存重構(gòu)
//4.1 獲取互斥鎖
String lockKey = "lock:shop:" + id;
Shop shop = null;
try {
boolean isLock = tryLock(lockKey);
// 4.2 判斷否獲取成功
if(!isLock){
//4.3 失敗,則休眠重試
Thread.sleep(50);
return queryWithMutex(id);
}
//4.4 成功,根據(jù)id查詢數(shù)據(jù)庫
shop = getById(id);
// 5.不存在,返回錯(cuò)誤
if(shop == null){
//將空值寫入redis
stringRedisTemplate.opsForValue().set(key,"",CACHE_NULL_TTL,TimeUnit.MINUTES);
//返回錯(cuò)誤信息
return null;
}
//6.寫入redis
stringRedisTemplate.opsForValue().set(key,JSONUtil.toJsonStr(shop),CACHE_NULL_TTL,TimeUnit.MINUTES);
}catch (Exception e){
throw new RuntimeException(e);
}
finally {
//7.釋放互斥鎖
unlock(lockKey);
}
return shop;
}
到了這里,關(guān)于Redis緩存穿透,雪崩,擊穿的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!