Redis缓存击穿和缓存雪崩、缓存穿透以及对应的解决方案
目錄
緩存擊穿
緩存擊穿的解決方案
緩存雪崩
緩存雪崩的解決方案
緩存穿透
布隆過濾器
緩存擊穿
一般我們會(huì)對(duì)緩存的key設(shè)置過期時(shí)間,在高并發(fā)下,如果在某一時(shí)刻這個(gè)key剛好過期,此時(shí)持續(xù)的大并發(fā)請(qǐng)求都會(huì)穿破緩存,直接命中DB,就像在一個(gè)屏障上鑿開了一個(gè)洞。
緩存擊穿的解決方案
1)? 通過分布式鎖或者隊(duì)列,使得同一個(gè)key只允許一個(gè)線程到數(shù)據(jù)庫(kù)查詢
2)定時(shí)預(yù)先更新緩存,避免發(fā)生緩存失效的情形
不過一般情況下單個(gè)緩存的擊穿很難對(duì)數(shù)據(jù)庫(kù)造成壓垮性的壓力
緩存雪崩
緩存雪崩是指緩存中的大量的key在同一時(shí)間失效,導(dǎo)致所有的請(qǐng)求都命中DB,使得其無法負(fù)載。簡(jiǎn)單來說就是大量key同時(shí)發(fā)生緩存擊穿的情形
緩存擊穿針對(duì)的是某一個(gè)設(shè)置了過期時(shí)間的緩存,緩存雪崩針對(duì)的是很多設(shè)置了過期時(shí)間的緩存
緩存雪崩的解決方案
1)? 通過分布式鎖或者隊(duì)列,使得同一個(gè)key只允許一個(gè)線程到數(shù)據(jù)庫(kù)查詢
2)定時(shí)預(yù)先更新緩存,避免同時(shí)發(fā)生緩存失效的情形
3)通過加隨機(jī)數(shù),使得不同的key在不同的時(shí)間過期
4)設(shè)置緩存永不過期
緩存穿透
緩存穿透,是指查詢一個(gè)數(shù)據(jù)庫(kù)一定不存在的數(shù)據(jù)。通常redis沒有緩存的時(shí)候,我們就會(huì)去訪問數(shù)據(jù)庫(kù)獲取數(shù)據(jù),此時(shí)如果數(shù)據(jù)庫(kù)也不存在數(shù)據(jù),那么每次對(duì)該key的請(qǐng)求都會(huì)命中數(shù)據(jù)庫(kù),在高并發(fā)情形下,就會(huì)導(dǎo)致數(shù)據(jù)庫(kù)壓力過大從而崩潰。
如果每次請(qǐng)求的數(shù)據(jù)都是同一個(gè)key,那么可以通過緩存空數(shù)據(jù)或者特殊字符串,比如&&來避免緩存穿透(需要對(duì)這個(gè)緩存設(shè)置一個(gè)過期時(shí)間,否則數(shù)據(jù)庫(kù)新增了這一數(shù)據(jù)也無法獲取到對(duì)應(yīng)值)
但是如果每次請(qǐng)求的key都不一樣,那么我們就需要其他的方法來判斷一個(gè)key是否存在于數(shù)據(jù)庫(kù)中,不能直接通過查詢數(shù)據(jù)庫(kù)的方式來判斷
因?yàn)榫彺娴耐谴罅康臄?shù)據(jù),直接存儲(chǔ)所有的數(shù)據(jù)顯然費(fèi)空間又費(fèi)時(shí)間,為了節(jié)省存儲(chǔ)空間,可以采用BitMap(位圖)的方式來標(biāo)記這個(gè)key是否出現(xiàn)過
對(duì)于每一個(gè)元素,我們通過哈希函數(shù)對(duì)key進(jìn)行運(yùn)算,得到一個(gè)下標(biāo),將其對(duì)應(yīng)的位圖上的值改為1,就表示該元素在這個(gè)集合存在。因?yàn)楣E鲎驳拇嬖?#xff0c;我們可以采用
1.擴(kuò)大數(shù)組的長(zhǎng)度或者說位圖容量 (空間消耗加大)
2.引入很多個(gè)哈希函數(shù) (耗時(shí))
來減小哈希碰撞的概率
實(shí)際使用中,我們既要節(jié)省空間,又要很高的計(jì)算效率,就必須在位圖容量和函數(shù)個(gè)數(shù)之間找到一個(gè)最優(yōu)解,布隆過濾器就幫助我們解決了這個(gè)問題
布隆過濾器
1970年由Burton Howard Bloom提出,其目的就是為了快速判斷一個(gè)集合里是否存在某一個(gè)元素
bloom過濾器實(shí)際是由一個(gè)長(zhǎng)位圖和k個(gè)不同的哈希函數(shù)組成的
其過程主要分為三步:
1.創(chuàng)建一個(gè)二進(jìn)制數(shù)組,所有的值都初始化為0
2.將集合里的每一個(gè)元素都通過k個(gè)hash函數(shù)運(yùn)算其在位圖的下標(biāo)
3.將對(duì)應(yīng)的下標(biāo)的值改為1
判斷某個(gè)元素是否存在于集合的時(shí)候,我們只需要判斷元素通過k個(gè)hash函數(shù)計(jì)算出來的下標(biāo)在位圖上是否都為1就可以了,如果全部為1,則表示該元素很可能存在;否則該元素就一定不存在(這是因?yàn)閔ash碰撞無法避免,會(huì)導(dǎo)致有一定的誤判率,會(huì)將不存在的元素誤判為存在)
這種把本來不存在布隆過濾器中的元素誤判為存在的情況,我們把它叫做假陽性(False Positive Probability,FPP)。
Funnel<String> funnel = new Funnel<String>() {@Overridepublic void funnel(String from, PrimitiveSink into) {into.putString(from, Charsets.UTF_8);}};// 創(chuàng)建符合條件的布隆過濾器 誤判率為0.1%,集合元素最大預(yù)計(jì)為一萬BloomFilter<String> filter = BloomFilter.create(funnel, 10000, 0.001);filter.put("chenpp");System.out.println(filter.mightContain("chenpp"));System.out.println(filter.mightContain("chenpp11"));如果在緩存中使用布隆過濾器,其流程圖如下:
首先每次在數(shù)據(jù)庫(kù)新增數(shù)據(jù)的時(shí)候,都需要把數(shù)據(jù)同步到BloomFilter中
在查詢數(shù)據(jù)的時(shí)候,先在布隆過濾器查詢,如果返回說沒有,那數(shù)據(jù)庫(kù)中也肯定沒有,就不需要查了,只有返回為存在的數(shù)據(jù)才需要查詢緩存和DB
?
總結(jié)
以上是生活随笔為你收集整理的Redis缓存击穿和缓存雪崩、缓存穿透以及对应的解决方案的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 使用Maven archetype 自定
- 下一篇: MySQL(一)SQL执行流程与MySQ