- 緩存在大併發系統中的重要做用不言而喻。緩存屬於內存操做,微秒或毫秒級別。在互聯網公司絕對繞不過這個緩存。緩存有不少mc,redis等。這裏描述的是redis.由於redis能夠持久化,而mc純內存,重啓機器數據就沒法找回。redis則還能夠從新從磁盤中導入數據。緩存則又有繞不開的問題。那就是雪崩,擊穿,穿透問題。
緩存雪崩:
-
- 現象:
影響輕則,查詢變慢,重則當請求併發更高時,出來大面積服務不可用。
-
- 緣由:
同一時間緩存大面積失效,就像沒有緩存同樣,全部的請求直接打到數據庫上來,DB扛不住掛了,若是是重要的庫,例如用戶庫,那牽聯就一大片了,瞬間倒一片。
-
- 案例:
電商首頁緩存,若是首頁的key所有都在某一時刻失效,恰好在那一時刻有秒殺活動,那這樣的話就全部的請求都被打到了DB。併發大的狀況下DB必然扛不住,沒有其餘降級之類的方案的話,DBA也只能重啓DB,可是這樣又會被新的流量搞掛。
-
- 解決方案:
批量往redis存數據的時候,把每一個key的失效時間加上個隨機數,這樣的話就能保證數據不會在同一個時間大面積失效。
緩存穿透:
-
- 現象與緣由:
就是指用戶不斷髮起請求的數據,在緩存和DB中都沒有,好比DB中的用戶ID是自增的,可是用戶請求傳了-1,或者是一個特別大的數字,這個時候用戶頗有可能就是一個攻擊者,這樣的功擊會致使DB的壓力過大,嚴重的話就是把DB搞掛了。由於每次都繞開了緩存直接查詢DB
-
- 解決方案:
- 方法一:在接口層增長校驗,不合法的參數直接返回。不相信任務調用方,根據本身提供的API接口規範來,做爲被調用方,要考慮可能任何的參數傳值。
- 方法二:在緩存查不到,DB中也沒有的狀況,能夠將對應的key的value寫爲null,或者其餘特殊值寫入緩存,同時將過時失效時間設置短一點,以避免影響正常狀況。這樣是能夠防止反覆用同一個ID來暴力攻擊。
- 方法三:正經常使用戶是不會這樣暴力功擊,只有是惡意者纔會這樣作,能夠在網關NG做一個配置項,爲每個IP設置訪問閥值。
- 方法四:高級用戶布隆過濾器(Bloom Filter),這個也能很好地防止緩存穿透。原理就是利用高效的數據結構和算法快速判斷出你這個Key是否在DB中存在,不存在你return就行了,存在你就去查了DB刷新KV再return。
緩存擊穿:
-
- 現象與緣由:
跟緩存雪崩相似,可是又有點不同。雪崩是由於大面積緩存失效,請求全打到DB;而緩存擊穿是指一個key是熱點,不停地扛住大併發請求,全都集中訪問此key,而當此key過時瞬間,持續的大併發就擊穿緩存,全都打在DB上。就又引起雪崩的問題。
-
- 解決方案:
設置熱點key不過時。或者加上互斥鎖。
總結:
這就是三者的區別,差很少,但又有一些區別。由於緩存雪崩、穿透和擊穿,是緩存最大的問題,要麼不出現,一旦出現就是致命性的問題
通常避免以上狀況發生咱們從三個時間段去分析下:redis
- 事前:Redis 高可用,主從+哨兵,Redis cluster,避免全盤崩潰。
- 事中:本地 ehcache 緩存 + Hystrix 限流+降級,避免** MySQL** 被打死。
- 過後:Redis 持久化 RDB+AOF,一旦重啓,自動從磁盤上加載數據,快速恢復緩存數據。
擴展知識:
能夠用限流組件,設置每秒的請求,有多少能經過組件,剩餘的未經過的請求,怎麼辦?走降級!能夠返回一些默認的值,或者友情提示,或者空白的值。
這樣的好處就是:數據庫絕對不會死,限流組件確保了每秒只有多少個請求能經過。 只要數據庫不死,就是說,對用戶來講,3/5 的請求都是能夠被處理的。 只要有 3/5 的請求能夠被處理,就意味着你的系統沒死,對用戶來講,可能就是點擊幾回刷不出來頁面,可是多點幾回,就能夠刷出來一次。
摘抄自網絡算法