緩存雪崩、穿透如何解決,如何確保Redis只緩存熱點數據?

關注 「Java藝術」一塊兒來充電吧!

  • 緩存雪崩如何解決?
    java

  • 緩存穿透如何解決?面試

  • 如何確保Redis緩存的都是熱點數據?redis

  • 如何更新緩存數據?數據庫

  • 如何處理請求傾斜?緩存

  • 實際業務場景下,如何選擇緩存數據結構微信


1
緩存雪崩


緩存雪崩簡單說就是全部請求都從緩存中拿不到數據,好比大批量數據同一時間過時。對於大批量數據同時過時的場景,能夠爲數據設置過時時間指定一個時間範圍內的隨機值,好比一天到一天零一小時之間的隨機值,但不適用於集合類型,好比hash。數據結構


還有小數場景,好比高峯流量致使Redis集羣崩潰;未配置持久化的redis無從節點Cluster集羣重啓、集羣遷移。當Redis集羣發生故障時,可先啓用內存緩存方案,好比Ehcache,同時根據狀況作限流與降級,最後快速重啓集羣,必須配置持久化策略,根據流量狀況擴展集羣。app


2
緩存穿透


緩存穿透簡單理解就是數據庫中也沒有對應的記錄,永遠都不會命中緩存。好比表中的記錄只有id從1000到100000,請求查詢id爲10000000的記錄。通常是惡意攻擊,針對這種狀況最好的處理方式就是判斷id的有效範圍,其它狀況能夠針對查詢的key緩存一個null值,並設置ttl過時時間。編輯器


3
如何確保Redis緩存的都是熱點數據


A、爲key設置ttl過時時間


適用於對實時性要求不高的業務場景;適用於能夠容忍獲取到的是過時數據的業務場景。過時時間會在每次讀寫key時刷新。爲確保緩存中不遺留垃圾數據,通常都會爲key設置過時時間,除了那些不會改變且一直會用到,也不會更新的數據,好比筆者前幾篇文章提到的IP庫。微服務


B、選擇緩存淘汰策略


選擇淘汰最近最少使用的緩存淘汰策略能夠保證緩存中都是熱點數據,但這個策略只會在內存吃緊的狀況下起效果,通常要保證緩存的數據都是熱點數據就是在redis內存不夠用的狀況下。建議及時作緩存數據清理,依靠緩存淘汰策略的時候性能也會有所降低。


C、緩存訪問次數,定時清除訪問次數少的記錄


好比用Sorted Set緩存key的讀次數,週期性的去刪除訪問次數小於多少的key。適用於hash等集合類型,計錄field的讀次數,缺點是每次請求都有統計次數的性能開銷。



4
如何更新緩存數據


A、在數據庫修改記錄時使用MQ隊列通知更新


適用於那種比較少改動的緩存記錄,好比用戶信息;適用於要求數據修改及時更新緩存的業務場景,如一些配置的修改要求及時生效。但不適用於要求很是實時的場景,好比商品庫存。


B、在修改數據庫記錄時直接更新緩存


這種方法與前一種方法均可利用AOP方式去更新,區別在於,前者解決多個服務之間的耦合問題,用於跨服務數據更新。小公司爲考慮成本問題不會爲每一個服務使用獨立的Redis集羣,後者只能用於單個服務內的數據更新。即使是多個微服務使用同一個Redis集羣,也不要經過共用key的方式共享緩存,不然耦合性太大,容易出問題。


C、定時任務批量更新


配合ttl使用,ttl的時間設置比定時任務週期長一點,避免數據過時了新的任務還沒執行完成。適用於實時性要求不是很高,且短期內大量數據更新的業務場景。好比數據庫有10w數據,每15分鐘都會有百分七八十的數據變動,且變動時間只在一分鐘內。


若是是集合類型、Hash類型,通常會配合Rename使用,只有全部數據寫入到redis成功,才原子性替換舊數據。且數據量大的狀況下使用pipeline批量寫入,避免使用hmset這類批量操做。使用hash這類集合類型時,必定要考慮到髒數據的問題。



5
如何處理請求傾斜問題


Cluster分槽會致使緩存數據傾斜,從而致使請求傾斜。假設一個三個小主從的Cluster集羣,平均分配槽位,大量的key落到第二個節點上,致使請求都偏向第二個節點。致使這個問題的主要緣由是,大量key爲hash、set、sorted sort類型,且每一個集合數據量都比較大。其次是HashTag的不合理使用。


解決方案,一是將大hash分段存儲,二是減小HashTag的使用,三是從新分配槽位,將第二個節點的槽位根據實際狀況分配一些給其它兩個節點。


6
實際業務場景下,如何選擇緩存數據結構


拿我最熟悉的廣告行業,舉幾個簡單例子。


a、判斷一個廣告單是否過時


使用hash、bitmap均可實現。bitmap適用於判斷true or false的業務需求。bitmap的讀寫速度都優於hash,且內存佔用少。但出於其它需求,我選擇hash。bitmap用於其它業務需求,如快速判斷offer每日展現數是否達到上限。



b、統計每一個渠道的拉取廣告次數


簡單的key-value以及hash都支持incr自增,且操做原子性。爲減小緩存中key的數據,我選擇hash,同時也由於hash支持hgetall,用於實時統計以及方便問題排查。



c、根據標籤限CAP


Capacity,即容量,如根據國家、城市、渠道、廣告主等標籤限制廣告的展現次數,一個廣告可能同時會匹配到多個標籤,當達到最小Capacity時,即斷定爲true。經過Sorted Set存儲一個廣告匹配的全部標籤,根據當前展現次數經過zcount獲取匹配的標籤總數,判斷zcount結果是否大於零便可。



d、過濾每日重複ip


如用於過濾短期內重複點擊廣告的用戶,只是舉個例子。這時就能夠利用HyperLogLog存儲IP,HyperLogLog會過濾重複數據,準確率有偏差,但對業務影響甚微。


僅爲我的觀點,假設你是面試者,歡迎留言寫下你的答案!




公衆號ID:javaskill
掃碼關注最新動態


本文分享自微信公衆號 - Java藝術(javaskill)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索