天天看點

KKB : Redis 緩存穿透,緩存擊穿,緩存雪崩問題

什麼是緩存?

廣義的緩存就是在第一次加載某些可能會複用資料的時候,在加載資料的同時,将資料放到一個指定的地點做儲存。再下次加載的時候,從這個指定地點去取資料。這裡加緩存是有一個前提的,就是從這個地方取資料,比從資料源取資料要快得多

java狹義一些的緩存,主要是指三大類

  1. 虛拟機緩存(cache)
  2. 分布式緩存(redis)
  3. 資料庫緩存

正常來說,速度從上到下一次減慢

緩存取值圖

程序首先會去本地緩存去取值,如果沒有值,就會去分布式緩存查詢,如果分布式緩存還沒有,最終會走到資料庫查詢。而且每次查詢到值都會存儲到上一級的緩存

KKB : Redis 緩存穿透,緩存擊穿,緩存雪崩問題

緩存雪崩

緩存雪崩簡單的解釋就是:由于原有緩存失效,所有原本應該通路緩存的請求都去查詢資料庫了,而對資料庫CPU和記憶體造成巨大壓力,嚴重的會造成資料庫當機,造成系統的崩潰

解決方案:在緩存失效後,通過加鎖或者隊列來控制讀資料庫寫緩存的線程數量。比如某個key隻允許一個線程查詢資料和寫緩存,其他線程等待。雖然能夠在一定的程度上緩解了資料庫的壓力但是于此同時又降低了系統的吞吐量

緩存穿透

緩存穿透是指使用者查詢資料,在資料庫沒有,自然在緩存中也不會有。這樣就導緻使用者查詢的時候,在緩存中找不到,每次都要去資料庫再查詢一遍,然後傳回空。這樣請求就繞過緩存直接查資料庫,這也是經常提的緩存命中率問題

解決方案:

1.如果查詢資料庫也為空,直接設定一個預設值存放到緩存,這樣第二次到緩沖中擷取就有值了,而不會繼續通路資料庫,這種辦法最簡單粗暴。

⒉.把空結果,也給緩存起來,這樣下次同樣的請求就可以直接傳回空了,既可以避免當查詢的值為空時引起的緩存穿透。同時也可以單獨設定個緩存區域存儲空值,對要查詢的key進行預先校驗,然後再放行給後面的正常緩存處理邏輯。

緩存擊穿

對于一些設定了過期時間的key,如果這些key可能會在某些時間點被超高并發地通路,是一種非常"熱點"的資料。這個時候,需要考慮一個問題:緩存被"擊穿"的問題,這個和緩存雪崩的差別在于這裡針對某一key緩存,緩存雪崩則是很多key。

熱點key:

某個key通路非常頻繁,當key失效的時候有大量線程來建構緩存,導緻負載增加,系統崩潰。

解決辦法:

①使用鎖,單機用synchronized,lock等,分布式用分布式鎖。

②緩存過期時間不設定,而是設定在key對應的value裡。如果檢測到存的時間超過過期時間則異步更新緩存。

分布式鎖在一下部落格中講解