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

對於緩存而言,redis

  1. 約束好key的規範,合理肯定Val值的大小,選擇合適的緩存介質(相應的根據實際的業務狀況分析,哪一種緩存方式合適 redis、zk、memcached 亦或者 local)。(生產實際案例:redis作緩存,因Val值過大的key太多,致使reids的性能出現了問題,形成業務不可用
  2. 合理分配緩存失效時間(緩存是物理有失效時間 ? 亦或者 在緩存的對象裏增長一個虛擬的失效時間,而物理上是沒有過時時長的或比較長的過時時間)
  3. 緩存沒值,是繼續輪詢獲取呢,仍是暫緩本次獲取(retry 次數和超時時間的處理)?仍是競爭鎖去查db呢?
  4. 合理加鎖控制分佈式下全局單線程查詢DB寫緩存操做

緩存穿透

程序在處理緩存時,通常是先從緩存查詢,若是緩存沒有這個key獲取爲null,則會從DB中查詢,並設置到緩存中去。數據庫

按這種作法,那查詢一個必定不存在的數據值,因爲緩存是不命中時須要從數據庫查詢,查不到數據則不寫入緩存,這將致使這個不存在的數據每次請求都要到數據庫去查詢,形成緩存穿透。後端

解決辦法

  1. 最好對於每個緩存key都有必定的規範約束,這樣在程序中對不符合parttern的key 的請求能夠拒絕。(但通常key都是經過程序自動生成的)
  2. 將可能出現的緩存key的組合方式的全部數值以hash形式存儲在一個很大的bitmap中<布隆過濾器>(須要考慮如何將這個可能出現的數據的hash值以後同步到bitmap中, eg. 後端每次新增一個可能的組合就同步一次,或者 窮舉),一個必定不存在的數據會被這個bitmap攔截掉,從而避免了對底層存儲系統的查詢壓力
  3. 經常使用: 若是對應在數據庫中的數據都不存在,咱們將此key對應的value設置爲一個默認的值,好比「NULL」,並設置一個緩存的失效時間。固然這個key的時效比正常的時效要小的多

有點相似於將一個key經過n個不一樣的hash函數定位成n個整數,而後將這n個整數定位在一個長度在M的初始數值爲0的數組下標上,設置該n個下標的數值爲1。 那隻要當查詢過來,用這n個hash函數定位斷定都爲1那基本就存在,只要有任一下標的數組值不是1,則表明不存在。數組

緩存雪崩

指的是大量緩存集中在一段時間內失效,發生大量的緩存穿透,全部的查詢都落在數據庫上,形成了緩存雪崩。緩存

解決辦法

  1. 這個沒有完美解決辦法,但能夠分析用戶行爲,儘可能讓失效時間點均勻分佈,設置不一樣的過時時間。
  2. 用加分佈式鎖或者分佈式隊列的方式保證緩存的單線程(進程)寫 (eg. redis的 SETNX,從而避免失效時大量的併發請求落到底層存儲系統上。在加鎖方法內先從緩存中再獲取一次(防止另外的線程優先獲取鎖已經寫入了緩存),沒有再查DB寫入緩存(固然也能夠: 在沒有獲取鎖(tryLock)的線程中一直輪詢緩存,至超限時)

緩存擊穿

指的是熱點key在某個特殊的場景時間內剛好失效了,剛好有大量併發請求過來了,形成DB壓力。併發

解決辦法

與緩存雪崩的解決方法相似: 用加鎖或者隊列的方式保證緩存的單線程(進程)寫,在加鎖方法內先從緩存中再獲取一次,沒有再查DB寫入緩存。 異步

還有一種比較好用的(針對緩存雪崩與緩存擊穿):分佈式

物理上的緩存是不設置超時時間的(或者超時時間比較長), 可是在緩存的對象上增長一個屬性來標識超時時間(此時間相對小)。 當獲取到數據後,校驗數據內部的標記時間,斷定是否快超時了,若是是,異步發起一個線程(控制好併發)去主動更新該緩存。memcached

這種方式會致使必定時間內,有些請求獲取緩存會拿到過時的值,看業務是否能接受而定。函數

相關文章
相關標籤/搜索