緩存穿透
很多項(xiàng)目在使用Redis或其他緩存框架的時(shí)候,都是先查詢緩存,查詢不的話再查詢數(shù)據(jù)庫,查到之后再放到內(nèi)存中;如果一個(gè)key值本身就不存在,那么每一次都會查詢數(shù)據(jù)庫,也就是常說的【緩存穿透】。
應(yīng)對方法:
如果在Redis中查詢不到,并且查詢數(shù)據(jù)庫也沒有結(jié)果,那么就將這個(gè)key寫入到Redis中,value=空,并設(shè)置一個(gè)超時(shí)過期時(shí)間,例如五分鐘,那么五分鐘以內(nèi)的對這個(gè)可以的所有查詢就可以攔截下來,如果數(shù)據(jù)庫有key對應(yīng)的數(shù)據(jù)了,那么五分鐘后Redis中的緩存過期,會訪問數(shù)據(jù)庫并加載緩存;但是如果被惡意攻擊,每次請求的key都不相同且不存在,那么依然會穿透到數(shù)據(jù)庫;
布隆過濾器:將可能存在的數(shù)據(jù)Hash到一個(gè)足夠大的bitmap上,它可以告訴你 “某個(gè)key一定不存在或者可能存在”,一個(gè)一定不存在的數(shù)據(jù)會被bitmap攔截。
緩存雪崩很多時(shí)候,Redis中的緩存是要設(shè)置過期時(shí)間的,假如Redis中的數(shù)據(jù),過期時(shí)間都設(shè)置成一樣的,那么到了時(shí)間之后,全部緩存過期失效,下一秒所有的請求都會訪問數(shù)據(jù)庫,那么數(shù)據(jù)庫可能因?yàn)樵L問量多大導(dǎo)致“崩潰”,這就是緩存雪崩。
應(yīng)對方法:
最暴力的解決辦法,緩存不設(shè)置自動過期時(shí)間,只要緩存不崩,數(shù)據(jù)庫就不會崩。
另外一個(gè)辦法,就是讓緩存過期時(shí)間不那么一致,比如一批緩存數(shù)據(jù)24小時(shí)后過期,那么就在這個(gè)基礎(chǔ)上,每條緩存的過期時(shí)間前后隨機(jī)1-6000秒(1-10分鐘)。
緩存并發(fā)大多數(shù)時(shí)候,我們的程序訪問Redis都不可能是單線程,那么當(dāng)多個(gè)Client并發(fā)對Redis進(jìn)行set key操作的時(shí)候,可能會產(chǎn)生一些問題;其實(shí)Redis本身是單線程的,這種時(shí)候會按照先后順序進(jìn)行操作;或者把操作放在隊(duì)列中,按順序執(zhí)行;
但比如這種情況:
token過期,有兩個(gè)線程都去重新獲取token;
線程1獲取token1;
線程2獲取到token2,此時(shí)token1過期;
線程1把token1放到Redis,再拿著token1去調(diào)用服務(wù),發(fā)現(xiàn)過期了,繼續(xù)去請求token3,此時(shí)token2過期;
線程2把token2放到Redis,再拿著token2去調(diào)用服務(wù),發(fā)現(xiàn)過期了,繼續(xù)去請求token4,此時(shí)token3過期;
... ...
這就需要我們在更新緩存的時(shí)候,做一些控制了。
我將持續(xù)分享Java開發(fā)、架構(gòu)設(shè)計(jì)、程序員職業(yè)發(fā)展等方面的見解,希望能得到你的關(guān)注。