redis擊穿 雪崩 穿透超詳細(xì)解決方案梳理
Redis擊穿
redis緩存擊穿是指某一個(gè)非常熱點(diǎn)的key(即在客戶端搜索的比較多的關(guān)鍵字)突然失效了,這時(shí)從客戶端發(fā)送的大量的請求在redis里找不到這個(gè)key,就會去數(shù)據(jù)里找,最終導(dǎo)致數(shù)據(jù)庫壓力過大崩掉。
解決方案:
1.將value的時(shí)效設(shè)置成永不過期 這種方式非常簡單粗暴但是安全可靠。但是非常占用空間對內(nèi)存消耗也是極大。個(gè)人并不建議使用該方法,應(yīng)該根據(jù)具體業(yè)務(wù)邏輯來操作。
2.使用Timetask做一個(gè)定時(shí)任務(wù) 使用Timetask做定時(shí),每隔一段時(shí)間對一些熱點(diǎn)key進(jìn)行數(shù)據(jù)庫查詢,將查詢出的結(jié)果更新至redis中。前條件是不會給數(shù)據(jù)庫過大的壓力。
3.通過synchronized+雙重檢查機(jī)制 當(dāng)發(fā)生reids穿透的時(shí)候,這時(shí)海量請求發(fā)送到數(shù)據(jù)庫。這時(shí)我們的解決辦法是只讓只讓一個(gè)線程去查詢這個(gè)熱點(diǎn)key,其它線程保持阻塞狀態(tài)(可以讓它們sleep幾秒)。當(dāng)這個(gè)進(jìn)入數(shù)據(jù)庫的線程查詢出key對應(yīng)的value時(shí),我們再將其同步至redis的緩存當(dāng)中,其它線程睡醒以后再重新去redis里邊請求數(shù)據(jù)。
例子:
private static volaite Object obj = new Object(); public String getValue(String key){ String value=redis.get(key,String.class); if(value==null||StringUtils.isBlank(value){ synchronized(obj){ //進(jìn)入synchronized以后再去redis里查一遍,防止上一個(gè)搶到鎖的線程已經(jīng)更新過了。 value=redis.get(key,String.class); if(value==null||StringUtils.isBlank(value){ value=db.query(key); redis.set(key,value,1000); } } } return value; }
缺點(diǎn):存在死鎖和線程阻塞的風(fēng)險(xiǎn)。
Redis雪崩
指的是當(dāng)海量的請求去查詢多個(gè)key時(shí),此時(shí)redis緩存中失效或者查不到,然后海量的請求都去都去db查詢,從而導(dǎo)致db壓力突然飆升崩潰。
出現(xiàn)原因:
1.key同時(shí)失效
2.redis本身崩潰了
解決方案:
1.設(shè)置緩存時(shí),隨機(jī)初始化其失效時(shí)間
如果是redis的key同時(shí)失效,可采取該辦法,具體失效時(shí)間根據(jù)業(yè)務(wù)情況決定…
2.將不同的熱點(diǎn)key放置到不同的節(jié)點(diǎn)上去
因redis一般都是集群部署,將不同的熱點(diǎn)key平均的放置到不同節(jié)點(diǎn),也可以有效避免雪崩。
3.將value的時(shí)效設(shè)置成永不過期
4.使用Timetask做一個(gè)定時(shí)任務(wù),在失效之前重新刷redis緩存
Redis穿透
因?yàn)椴涣加脩魫阂忸l繁查詢才會對系統(tǒng)造成很大的問題: key緩存并且數(shù)據(jù)庫不存在,所以每次查詢都會查詢數(shù)據(jù)庫從而導(dǎo)致數(shù)據(jù)庫崩潰。
(例如:我們在數(shù)據(jù)庫存放的數(shù)據(jù)其主鍵都是自增且沒有負(fù)數(shù)的,某些黑客就利用這一點(diǎn),不斷用主鍵id為-1的參數(shù)來發(fā)起海量查詢請求,導(dǎo)致這些請求在redis中查不到相應(yīng)的數(shù)據(jù),只能去數(shù)據(jù)庫中查詢,從而導(dǎo)致數(shù)據(jù)庫崩潰。)
解決方案:
1.當(dāng)類似的請求發(fā)過來,無論查出什么結(jié)果都放入redis緩存
這樣解決當(dāng)他下次再用同一個(gè)參數(shù)發(fā)起請求時(shí),會直接進(jìn)到redis里邊去,不會再進(jìn)入數(shù)據(jù)庫。
2.拉黑其ip
3.對請求的參數(shù)進(jìn)行合法性校驗(yàn),在判斷其不合法的前提下直接return掉
4.使用布隆過濾器
可以將布隆過濾器理解成一個(gè)白名單或者黑名單,它的作用就是判斷一個(gè)元素是否存在于這個(gè)過濾器。
白名單: 過濾器里有數(shù)據(jù)庫中所有的合法的參數(shù)key,請求經(jīng)過布隆過濾器,布隆過濾器判斷這個(gè)請求的key在不在過濾器,在就放行讓請求進(jìn)入redis,不在就直接return空數(shù)據(jù)。
public static void main(String[] args){ Config config = new Config(); config.useSingleServer().setAddress("redis://127.0.0.1:6379"); config.useSingleServer().setPassword("1234"); //構(gòu)造Redsson RedissonClient redisson = Redisson.create(config); RBloomFilter<String> bloomFilter = redisson.getBloomFilter("phoneList");//給我們自己定義的布隆過濾器取名叫phoneList,名字隨便取 //初始化布隆過濾器設(shè)置預(yù)計(jì)元素為100000000L, 誤差率為3% bloomFilter.tryInit(100000000L,0.03); //將10086插入到布隆過濾器中 bloomFilter.add("10086"); //判斷下面號碼是否存在布隆過濾器中 //false System.out.println("123456"); //true System.out.println("10086"); }
缺點(diǎn):
布隆過濾器可能會造成誤判,從而穿透redis進(jìn)入DB,但是這個(gè)誤判概率是非常小的。
以上就是redis擊穿 雪崩 穿透超詳細(xì)解決方案梳理的詳細(xì)內(nèi)容,更多關(guān)于redis 擊穿 雪崩 穿透的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
基于Redis實(shí)現(xiàn)短信驗(yàn)證碼登錄項(xiàng)目示例(附源碼)
手機(jī)登錄驗(yàn)證在很多網(wǎng)頁上都得到使用,本文主要介紹了基于Redis實(shí)現(xiàn)短信驗(yàn)證碼登錄項(xiàng)目示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-05-05Redis如何在項(xiàng)目中合理使用經(jīng)驗(yàn)分享
這篇文章主要給大家介紹了關(guān)于Redis如何在項(xiàng)目中合理使用的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用Redis具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2019-04-04Redis分布式鎖方案設(shè)計(jì)之防止訂單重復(fù)提交或支付
這篇文章主要為大家介紹了Redis分布式鎖之防止訂單重復(fù)提交或支付方案設(shè)計(jì)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-09-09Redis 中spark參數(shù)executor-cores引起的異常解決辦法
這篇文章主要介紹了Redis 中spark參數(shù)executor-cores引起的異常解決辦法的相關(guān)資料,需要的朋友可以參考下2017-03-03