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


                <p><br></p><ul class="list-paddingleft-2" style="list-style-type: disc;margin-left: 8px;margin-right: 8px;"><li><p class=""><span style="font-size: 15px;">緩存雪崩如何解決?</span><br></p></li><li><p class=""><span style="font-size: 15px;">緩存穿透如何解決?</span></p></li><li><p class=""><span style="font-size: 15px;">如何確保Redis緩存的都是熱點數據?</span></p></li><li><p class=""><span style="font-size: 15px;">如何更新緩存數據?</span></p></li><li><p class=""><span style="font-size: 15px;">如何處理請求傾斜?</span></p></li><li><p class=""><span style="font-size: 15px;">實際業務場景下,如何選擇緩存數據結構</span></p></li></ul><p class=""><br></p><section style="margin-left: 8px;margin-right: 8px;"><span style="font-weight: 700;font-size: 20px;color: rgb(0, 0, 0);">緩存雪崩</span></section><section style="margin-left: 8px;margin-right: 8px;"><span style="font-size: 15px;">緩存雪崩簡單說就是所有請求都從緩存中拿不到數據,比如大批量數據同一時間過期。對於大批量數據同時過期的場景,可以為數據設置過期時間指定一個時間范圍內的隨機值,比如一天到一天零一小時之間的隨機值,但不適用於集合類型,比如hash。</span></section><p class=""><br></p><section style="margin-left: 8px;margin-right: 8px;"><span style="font-size: 15px;">還有小數場景,比如高峰流量導致Redis集群崩潰;未配置持久化的redis無從節點Cluster集群重啟、集群遷移。當Redis集群發生故障時,可先啟用內存緩存方案,比如Ehcache,同時根據情況做限流與降級,最后快速重啟集群,必須配置持久化策略,根據流量情況擴展集群。</span></section><p class=""><br></p><section style="margin-left: 8px;margin-right: 8px;"><span style="font-weight: 700;font-size: 20px;color: rgb(0, 0, 0);">緩存穿透</span></section><section style="margin-left: 8px;margin-right: 8px;"><span style="font-size: 15px;">緩存穿透簡單理解就是數據庫中也沒有對應的記錄,永遠都不會命中緩存。比如表中的記錄只有id從1000到100000,請求查詢id為10000000的記錄。一般是惡意攻擊,針對這種情況最好的處理方式就是判斷id的有效范圍,其它情況可以針對查詢的key緩存一個null值,並設置ttl過期時間。</span></section><p class=""><br></p><section style="margin-left: 8px;margin-right: 8px;"><span style="font-weight: bold;color: rgb(0, 0, 0);font-size: 20px;">如何確保Redis緩存的都是熱點數據</span></section><section data-role="outer" label="Powered by 135editor.com" style="font-size: 16px;"><section class="" data-role="paragraph"><p><br></p></section></section><section style="text-indent: 2em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 15px;">A、為key設置ttl過期時間</span></section><p><br></p><p class=""><br></p><section style="margin-left: 8px;margin-right: 8px;"><span style="font-size: 15px;">適用於對實時性要求不高的業務場景;適用於可以容忍獲取到的是過期數據的業務場景。過期時間會在每次讀寫key時刷新。為確保緩存中不遺留垃圾數據,一般都會為key設置過期時間,除了那些不會改變且一直會用到,也不會更新的數據,比如筆者前幾篇文章提到的IP庫。</span></section><p class=""><br></p><p><br></p><section style="text-indent: 2em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 15px;">B、選擇緩存淘汰策略</span></section><p><br></p><p class=""><br></p><section style="margin-left: 8px;margin-right: 8px;"><span style="font-size: 15px;">選擇淘汰最近最少使用的緩存淘汰策略可以保證緩存中都是熱點數據,但這個策略只會在內存吃緊的情況下起效果,一般要保證緩存的數據都是熱點數據就是在redis內存不夠用的情況下。建議及時做緩存數據清理,依靠緩存淘汰策略的時候性能也會有所下降。</span></section><p class=""><br></p><p><br></p><section style="text-indent: 2em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 15px;">C、緩存訪問次數,定時清除訪問次數少的記錄</span></section><p><br></p><p class=""><br></p><section style="margin-left: 8px;margin-right: 8px;"><span style="font-size: 15px;">比如用Sorted Set緩存key的讀次數,周期性的去刪除訪問次數小於多少的key。適用於hash等集合類型,計錄field的讀次數,缺點是每次請求都有統計次數的性能開銷。</span></section><p class=""><br></p><p class=""><br></p><section style="margin-left: 8px;margin-right: 8px;"><span style="font-weight: bold;color: rgb(0, 0, 0);font-size: 20px;">如何更新緩存數據</span></section><section data-role="outer" label="Powered by 135editor.com" style="font-size: 16px;"><section class="" data-role="paragraph"><p><br></p></section></section><section style="text-indent: 2em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 15px;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;">A、在數據庫修改記錄時使用MQ隊列通知更新</span><br></section><p><br></p><p class=""><br></p><section style="margin-left: 8px;margin-right: 8px;"><span style="font-size: 15px;">適用於那種比較少改動的緩存記錄,比如用戶信息;適用於要求數據修改及時更新緩存的業務場景,如一些配置的修改要求及時生效。但不適用於要求非常實時的場景,比如商品庫存。</span></section><p class=""><br></p><p><br></p><section style="text-indent: 2em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 15px;">B、在修改數據庫記錄時直接更新緩存</span></section><p><br></p><p class=""><br></p><section style="margin-left: 8px;margin-right: 8px;"><span style="font-size: 15px;">這種方法與前一種方法都可利用AOP方式去更新,區別在於,前者解決多個服務之間的耦合問題,用於跨服務數據更新。小公司為考慮成本問題不會為每個服務使用獨立的Redis集群,后者只能用於單個服務內的數據更新。即便是多個微服務使用同一個Redis集群,也不要通過共用key的方式共享緩存,否則耦合性太大,容易出問題。</span></section><p class=""><br></p><p><br></p><section style="text-indent: 2em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 15px;">C、定時任務批量更新</span></section><p><br></p><p class=""><br></p><section style="margin-left: 8px;margin-right: 8px;"><span style="font-size: 15px;">配合ttl使用,ttl的時間設置比定時任務周期長一點,避免數據過期了新的任務還沒執行完成。適用於實時性要求不是很高,且短時間內大量數據更新的業務場景。比如數據庫有10w數據,每15分鍾都會有百分七八十的數據變更,且變更時間只在一分鍾內。</span></section><p class=""><br></p><section style="margin-left: 8px;margin-right: 8px;"><span style="font-size: 15px;">如果是集合類型、Hash類型,一般會配合Rename使用,只有所有數據寫入到redis成功,才原子性替換舊數據。且數據量大的情況下使用pipeline批量寫入,避免使用hmset這類批量操作。使用hash這類集合類型時,一定要考慮到臟數據的問題。</span></section><p class=""><br></p><p class=""><br></p><section style="margin-left: 8px;margin-right: 8px;"><span style="font-weight: bold;color: rgb(0, 0, 0);font-size: 20px;">如何處理請求傾斜問題</span></section><section data-role="outer" label="Powered by 135editor.com" style="font-size: 16px;"><section class="" data-role="paragraph"><p><br></p></section></section><p class=""><br></p><section style="margin-left: 8px;margin-right: 8px;"><span style="font-size: 15px;">Cluster分槽會導致緩存數據傾斜,從而導致請求傾斜。假設一個三個小主從的Cluster集群,平均分配槽位,大量的key落到第二個節點上,導致請求都偏向第二個節點。導致這個問題的主要原因是,大量key為hash、set、sorted sort類型,且每個集合數據量都比較大。其次是HashTag的不合理使用。</span></section><p class=""><br></p><section style="margin-left: 8px;margin-right: 8px;"><span style="font-size: 15px;">解決方案,一是將大hash分段存儲,二是減少HashTag的使用,三是重新分配槽位,將第二個節點的槽位根據實際情況分配一些給其它兩個節點。</span></section><p class=""><br></p><section style="margin-left: 8px;margin-right: 8px;"><span style="font-weight: bold;color: rgb(0, 0, 0);font-size: 20px;">實際業務場景下,如何選擇緩存數據結構</span></section><p><br></p><section style="margin-left: 8px;margin-right: 8px;"><span style="font-size: 15px;">拿我最熟悉的廣告行業,舉幾個簡單例子。</span></section><p class=""><br></p><p><br></p><section style="text-indent: 2em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 15px;">a、判斷一個廣告單是否過期</span></section><p><br></p><p class=""><br></p><section style="margin-left: 8px;margin-right: 8px;"><span style="font-size: 15px;">使用hash、bitmap都可實現。bitmap適用於判斷true or false的業務需求。bitmap的讀寫速度都優於hash,且內存占用少。但出於其它需求,我選擇hash。bitmap用於其它業務需求,如快速判斷offer每日展示數是否達到上限。</span></section><p class=""><br></p><p class=""><br></p><p><br></p><section style="text-indent: 2em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 15px;">b、統計每個渠道的拉取廣告次數</span></section><p><br></p><p class=""><br></p><section style="margin-left: 8px;margin-right: 8px;"><span style="font-size: 15px;">簡單的key-value以及hash都支持incr自增,且操作原子性。為減少緩存中key的數據,我選擇hash,同時也因為hash支持hgetall,用於實時統計以及方便問題排查。</span></section><p class=""><br></p><p class=""><br></p><p><br></p><section style="text-indent: 2em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 15px;">c、根據標簽限CAP</span></section><p><br></p><p class=""><br></p><section style="margin-left: 8px;margin-right: 8px;"><span style="font-size: 15px;">Capacity,即容量,如根據國家、城市、渠道、廣告主等標簽限制廣告的展示次數,一個廣告可能同時會匹配到多個標簽,當達到最小Capacity時,即判定為true。通過Sorted Set存儲一個廣告匹配的所有標簽,根據當前展示次數通過zcount獲取匹配的標簽總數,判斷zcount結果是否大於零即可。</span></section><p class=""><br></p><p class=""><br></p><p><br></p><section style="text-indent: 2em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 15px;">d、過濾每日重復ip</span></section><p><br></p><p class=""><br></p><section style="margin-left: 8px;margin-right: 8px;"><span style="font-size: 15px;">如用於過濾短時間內重復點擊廣告的用戶,只是舉個例子。這時就可以利用HyperLogLog存儲IP,HyperLogLog會過濾重復數據,准確率有誤差,但對業務影響甚微。</span></section><p class=""><br></p><section style="margin-left: 8px;margin-right: 8px;"><span style="font-size: 15px;">僅為個人觀點,假設你是面試者,歡迎留言寫下你的答案!</span></section><section style="margin-left: 8px;margin-right: 8px;"><span style="font-size: 15px;"><br mpa-from-tpl="t"></span></section>

原文地址:https://mp.weixin.qq.com/s/-aOHMe3uOqiJt2Km4fkwGg


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM