redis之緩存雪崩、緩存穿透、緩存擊穿

緩存雪崩


處理緩存雪崩在批量往**Redis**存數據的時候,把每個Key的失效時間都加個隨機值就好了,這樣可以保證數據不會在同一時間大面積失效,我相信,Redis這點流量還是頂得住的。

```java? setRedis(Key,value,time + Math.random() * 10000);

如果**Redis**是集群部署,將熱點數據均勻分布在不同的**Redis**庫中也能避免全部失效的問題,不過本渣我在生產環(huán)境中操作集群的時候,單個服務都是對應的單個**Redis**分片,是為了方便數據的管理,但是也同樣有了可能會失效這樣的弊端,失效時間隨機是個好策略。

或者設置熱點數據永遠不過期,有更新操作就更新緩存就好了(比如運維更新了首頁商品,那你刷下緩存就完事了,不要設置過期時間),電商首頁的數據也可以用這個操作,保險。

解決方法:

1、 使用快速失敗的熔斷策略,減少DB瞬間壓力

2、 使用主從模式和集群模式來盡量保證緩存服務的高可用

緩存穿透

緩存穿透是指緩存和數據庫中都沒有的數據,而用戶不斷發(fā)起請求。

Eg: 我們數據庫的 id 都是1開始自增上去的,如發(fā)起為id值為 -1 的數據或 id 為特別大不存在的數據。這時的用戶很可能是攻擊者,攻擊會導致數據庫壓力過大,嚴重會擊垮數據庫。


像這種你如果不對參數做校驗,數據庫id都是大于0的,我一直用小于0的參數去請求你,每次都能繞開Redis直接打到數據庫,數據庫也查不到,每次都這樣,并發(fā)高點就容易崩掉了。

解決方案:緩存穿透? 在接口層增加校驗,比如用戶鑒權校驗,參數做校驗,不合法的參數直接代碼Return,比如:id 做基礎校驗,id <=0的直接攔截等。


舉個簡單的例子,你這個接口是分頁查詢的,但是你沒對分頁參數的大小做限制,調用的人萬一一口氣查 Integer.MAX_VALUE 一次請求就要你幾秒,多幾個并發(fā)你不就掛了么?是公司同事調用還好大不了發(fā)現了改掉,但是如果是黑客或者競爭對手呢?在你雙十一當天就調你這個接口會發(fā)生什么,就不用我說了吧。這是之前的Leader跟我說的,我覺得大家也都應該了解下。**


從緩存取不到的數據,在數據庫中也沒有取到,這時也可以將對應Key的Value對寫為null、位置錯誤、稍后重試這樣的值具體取啥問產品,或者看具體的場景,緩存有效時間可以設置短點,如30秒(設置太長會導致正常情況也沒法使用)。

這樣就可以防止攻擊用戶反復用同一個id暴力攻擊。

另外高級算法

Redis**還有一個高級用法**布隆過濾器(Bloom Filter)**這個也能很好的防止緩存穿透的發(fā)生,他的原理也很簡單就是利用高效的數據結構和算法快速判斷出你這個Key是否在數據庫中存在,不存在你return就好了,存在你就去查了DB刷新KV再return。

布隆過濾器

布隆過濾器可以用于檢索一個元素是否在一個集合中。它的優(yōu)點是空間效率和查詢時間都遠遠超過一般的算法,缺點是有一定的誤識別率和刪除困難。


用很小的空間,解決上述類似問題

實現原理:

當一個元素被加入集合時,通過k個散列函數將這個元素映射成一個位數組中的k個點,把它們置為1.檢索時,我們只要看看這些點是不是都時1就(大約)知道集合中有沒有它了:

如果這些點有任何一個0,則被檢元素一定不在;如果都是1,則被檢元素很可能在,這就是布隆過濾器的基本思想

一個很長的二機制向量和若干個哈希函數。

常用的幾個應用場景:

1、 cerberus在收集監(jiān)控數據的時候, 有的系統的監(jiān)控項量會很大,需要檢查一個監(jiān)控項的名字是否已經被記錄到db過了, 如果沒有的話就需要寫入db.


2、爬蟲過濾已抓到的url就不再抓,可用bloom

filter過濾

3、垃圾郵件過濾。如果用哈希表,每存儲一億個email地址,就需要 1.6GB的內存(用哈希表實現的具體辦法是將每一個 email地址對應成一個八字節(jié)的信息指紋,然后將這些信息指紋存入哈希表,由于哈希表的存儲效率一般只有 50%,因此一個 email地址需要占用十六個字節(jié)。一億個地址大約要 1.6GB,即十六億字節(jié)的內存)。因此存貯幾十億個郵件地址可能需要上百 GB的內存。而Bloom Filter只需要哈希表 1/8到 1/4 的大小就能解決同樣的問題。

緩存擊穿

緩存擊穿是指一個key非常熱點,在不停的扛著大并發(fā),大并發(fā)集中對這個點進行訪問,當這個key在失效的瞬間,持續(xù)的大并發(fā)就穿破緩存,直接請求數據庫,就像在一個完好無損的桶上鑿開一個洞。

緩存擊穿的解決辦法是:設置熱點數據永遠不過期。或者加上互斥鎖就能搞定

具體的解決方式:

1、 可以使用互斥鎖更新,保證同一進程中針對同一各數據不會并發(fā)請求到DB,減小DB壓力。

2、 使用隨機退避方式,失效時隨機sleep一個很短的時間,再次查詢,如果失敗再執(zhí)行更新。

3、 針對多各熱點key同時失效的問題,可以在緩存時使用固定時間加上一個小的隨機數,

避免大量熱點key同一時刻失效


一般避免以上情況發(fā)生我們從三個時間段去分析下:


?-事前:**Redis** 高可用,主從+哨兵,**Redis

cluster**,避免全盤崩潰。

?-事中:本地**ehcache** 緩存 + **Hystrix** 限流+降級,避免** MySQL** 被打死。

?-事后:**Redis** 持久化**RDB**+**AOF**,一旦重啟,自動從磁盤上加載數據,快速恢復緩存數據。

?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容