兩分鐘講透緩存穿透,你明白了嗎?
本文轉(zhuǎn)載自微信公眾號(hào)「后端技術(shù)小牛說(shuō)」,作者后端技術(shù)小牛說(shuō) 。轉(zhuǎn)載本文請(qǐng)聯(lián)系后端技術(shù)小牛說(shuō)公眾號(hào)。
由于redis是內(nèi)存型數(shù)據(jù)庫(kù),往往會(huì)被當(dāng)做緩存使用,那所以問(wèn)到redis相關(guān)知識(shí)點(diǎn),緩存這層是繞不開的。今天咱來(lái)嘮嘮緩存穿透。
先來(lái)看看緩存穿透的定義:緩存穿透,注意,關(guān)鍵在透這個(gè)詞上,就是不僅把緩存層打透了,也把數(shù)據(jù)庫(kù)打透了,即查詢一個(gè)數(shù)據(jù)庫(kù)也不存在的數(shù)據(jù)。
由于數(shù)據(jù)庫(kù)不存在這個(gè)值,那肯定緩存也不會(huì)有嘛,所以每次有這種垃圾查詢請(qǐng)求,都會(huì)打到數(shù)據(jù)庫(kù)上,對(duì)數(shù)據(jù)庫(kù)造成負(fù)擔(dān)。
那咋辦呢?
今天介紹兩個(gè)辦法:
- 布隆過(guò)濾器
- 緩存空對(duì)象
布隆過(guò)濾器
相信不少同學(xué)面試時(shí)被問(wèn)過(guò)場(chǎng)景設(shè)計(jì)題:如果目前我們有個(gè)營(yíng)銷垃圾郵箱的匯總表,我們希望設(shè)計(jì)一個(gè)高效的攔截過(guò)濾器,怎么設(shè)計(jì)呢?
大家肯定脫口而出:hashmap/hashset。
對(duì),這個(gè)思路一點(diǎn)沒(méi)錯(cuò),如果我們的郵箱匯總表不大,當(dāng)然可以這么干。但如果匯總表稍微大一點(diǎn)點(diǎn)比如上到10億,那就不能這么干了。一般來(lái)說(shuō)面試官會(huì)回答:這么做占用空間太大,服務(wù)器內(nèi)存撐不住,可以換一個(gè)思路,我們的這個(gè)業(yè)務(wù)可以允許一定的誤報(bào)。
既然面試官都給提示了,那咱就往擠壓內(nèi)存占用的思路去考慮,既然又希望減少空間,又能接受誤報(bào),可以考慮這個(gè)思路。
首先我們先設(shè)置一個(gè)空bit數(shù)組,初始全0:
設(shè)計(jì)k個(gè)hash映射函數(shù),這k個(gè)映射函數(shù)各不相同,然后開啟一個(gè)for循環(huán),把在匯總表中的郵箱通過(guò)這個(gè)映射函數(shù)得到數(shù)組指定位置,并置為1。比如這樣:
然后這樣
下次用戶有想查詢的郵箱,可以通過(guò)這一系列hash函數(shù),判斷對(duì)應(yīng)位置是否全為1。如果是,則很大概率就是垃圾郵箱了。為啥說(shuō)是很大概率,因?yàn)橥耆煌淖侄危谝粋€(gè)hash函數(shù)中,映射也會(huì)相同的。
那如何減少誤判概率?增加hash函數(shù)個(gè)數(shù),增加這個(gè)數(shù)組長(zhǎng)度。
最后提一下,這個(gè)數(shù)組可以就認(rèn)為是布隆過(guò)濾器。
緩存空對(duì)象
這個(gè)就很好理解了。咱們一般定義的查詢邏輯,是這樣
- 用戶發(fā)送查詢請(qǐng)求
- 緩存層收到請(qǐng)求查看緩存是否存在該值,存在即返回,不存在走步驟3
- 數(shù)據(jù)庫(kù)收到查詢請(qǐng)求,查詢?cè)撝担绻嬖?,就返回,并把值添加到緩存層上。不存在直接返?/li>
舉例來(lái)說(shuō),我們用了個(gè)員工id和其對(duì)應(yīng)的工資表。如果員工有100個(gè)人,那我們id肯定是1-100排列。如果此時(shí)有個(gè)請(qǐng)求,想查詢id=1000的,那肯定啥也查不到,會(huì)被直接返回。
而緩存空對(duì)象,做的就是把這個(gè)值也緩存下來(lái),即在緩存層中,添加一個(gè)id為1000,值為null的鍵值對(duì)。下次有對(duì)id為1000的請(qǐng)求,查詢直接打到緩存上,減少了數(shù)據(jù)庫(kù)壓力。
但這種操作會(huì)增加內(nèi)存開銷,所以如果采用這種方法,一般空對(duì)象緩存的過(guò)期時(shí)間極短。
參考:
https://blog.csdn.net/qq_26222859/article/details/80831263
https://zhuanlan.zhihu.com/p/72378274