聊聊Redis中如何應對緩存熱key問題?常用方案分享

redis中如何應對熱key問題?下面本篇文章就來給大家介紹一下redis緩存熱key問題的常用解決方案,希望對大家有所幫助!

聊聊Redis中如何應對緩存熱key問題?常用方案分享

? ? ? ?做一些C端業務,不可避免的要引入一級緩存來代替數據庫的壓力并且減少業務響應時間,其實每次引入一個中間件來解決問題的同時,必然會帶來很多新的問題需要注意,比如上篇文章《數據庫與緩存一致性實戰》中提到的如何做緩存的一致性。那么其實還會有一些其他問題比如使用Redis作為一級緩存時可能帶來的熱key、大key等問題,本文我們就熱key(hot key)問題來討論,如何合理的解決熱key問題。

背景

? ? ? ? 熱key是什么問題,如何導致的?

? ? ? ? 一般來說,我們使用的緩存Redis都是多節點的集群版,對某個key進行讀寫時,會根據該key的hash計算出對應的slot,根據這個slot就能找到與之對應的分片(一個master和多個slave組成的一組redis集群)來存取該K-V。但是在實際應用過程中,對于某些特定業務或者一些特定的時段(比如電商業務的商品秒殺活動),可能會發生大量的請求訪問同一個key。所有的請求(且這類請求讀寫比例非常高)都會落到同一個redis server上,該redis的負載就會嚴重加劇,此時整個系統增加新redis實例也沒有任何用處,因為根據hash算法,同一個key的請求還是會落到同一臺新機器上,該機器依然會成為系統瓶頸2,甚至造成整個集群宕掉,若此熱點key的value 也比較大,也會造成網卡達到瓶頸,這種問題稱為 “熱key” 問題。【相關推薦:Redis視頻教程

? ? ? ? 如下圖1、2所示,分別是正常redis cluster集群和使用一層proxy代理的redis 集群key訪問。

聊聊Redis中如何應對緩存熱key問題?常用方案分享

聊聊Redis中如何應對緩存熱key問題?常用方案分享

? ? ? ? 如上所說,熱key會給集群中的少部分節點帶來超高的負載壓力,如果不正確處理,那么這些節點宕機都有可能,從而會影響整個緩存集群的運作,因此我們必須及時發現熱key、解決熱key問題。

1.熱key探測

? ? ? ? 熱key探測,看到由于redis集群的分散性以及熱點key帶來的一些顯著影響,我們可以通過由粗及細的思考流程來做熱點key探測的方案。

1.1 集群中每個slot的qps監控

? ? ? ? 熱key最明顯的影響是整個redis集群中的qps并沒有那么大的前提下,流量分布在集群中slot不均的問題,那么我們可以最先想到的就是對于每個slot中的流量做監控,上報之后做每個slot的流量對比,就能在熱key出現時發現影響到的具體slot。雖然這個監控最為方便,但是粒度過于粗了,僅適用于前期集群監控方案,并不適用于精準探測到熱key的場景。

1.2 proxy的代理機制作為整個流量入口統計

? ? ? ? 如果我們使用的是圖2的redis集群proxy代理模式,由于所有的請求都會先到proxy再到具體的slot節點,那么這個熱點key的探測統計就可以放在proxy中做,在proxy中基于時間滑動窗口,對每個key做計數,然后統計出超出對應閾值的key。為了防止過多冗余的統計,還可以設定一些規則,僅統計對應前綴和類型的key。這種方式需要至少有proxy的代理機制,對于redis架構有要求。

1.3 redis基于LFU的熱點key發現機制

? ? ? ? redis 4.0以上的版本支持了每個節點上的基于LFU的熱點key發現機制,使用redis-cli –hotkeys即可,執行redis-cli時加上–hotkeys選項。可以定時在節點中使用該命令來發現對應熱點key。

聊聊Redis中如何應對緩存熱key問題?常用方案分享

? ? ? ? 如下所示,可以看到redis-cli –hotkeys的執行結果,熱key的統計信息,這個命令的執行時間較長,可以設置定時執行來統計。

1.4 基于Redis客戶端做探測

? ? ? ? 由于redis的命令每次都是從客戶端發出,基于此我們可以在redis client的一些代碼處進行統計計數,每個client做基于時間滑動窗口的統計,超過一定的閾值之后上報至server,然后統一由server下發至各個client,并且配置對應的過期時間。

? ? ? ? 這個方式看起來更優美,其實在一些應用場景中并不是那么合適,因為在client端這一側的改造,會給運行的進程帶來更大的內存開銷,更直接的來說,對于Javagolang這種自動內存管理的語言,會更加頻繁的創建對象,從而觸發gc導致接口響應耗時增加的問題,這個反而是不太容易預料到的事情。

? ? ? ? 最終可以通過各個公司的基建,做出對應的選擇。

2.熱key解決

? ? ? ? 通過上述幾種方式我們探測到了對應熱key或者熱slot,那么我們就要解決對應的熱key問題。解決熱key也有好幾種思路可以參考,我們一個一個捋一下。

2.1 對特定key或slot做限流

? ? ? ? 一種最簡單粗暴的方式,對于特定的slot或者熱key做限流,這個方案明顯對于業務來說是有損的,所以建議只用在出現線上問題,需要止損的時候進行特定的限流。

2.2 使用二級(本地)緩存

? ? ? ? 本地緩存也是一個最常用的解決方案,既然我們的一級緩存扛不住這么大的壓力,就再加一個二級緩存吧。由于每個請求都是由service發出的,這個二級緩存加在service端是再合適不過了,因此可以在服務端每次獲取到對應熱key時,使用本地緩存存儲一份,等本地緩存過期后再重新請求,降低redis集群壓力。以java為例,guavaCache就是現成的工具。以下示例:

????//本地緩存初始化以及構造 ????private?static?LoadingCache<string>&gt;?configCache ????????????=?CacheBuilder.newBuilder() ????????????.concurrencyLevel(8)??//并發讀寫的級別,建議設置cpu核數 ????????????.expireAfterWrite(10,?TimeUnit.SECONDS)??//寫入數據后多久過期 ????????????.initialCapacity(10)?//初始化cache的容器大小 ????????????.maximumSize(10)//cache的容器最大 ????????????.recordStats() ????????????//?build方法中可以指定CacheLoader,在緩存不存在時通過CacheLoader的實現自動加載緩存 ????????????.build(new?CacheLoader<string>&gt;()?{ ????????????????@Override ????????????????public?List<object>?load(String?hotKey)?throws?Exception?{ ???????????????????? ????????????????} ????????????}); ???? ????//本地緩存獲取 ????Object?result?=?configCache.get(key);</object></string></string>

? ? ? ? 本地緩存對于我們的最大的影響就是數據不一致的問題,我們設置多長的緩存過期時間,就會導致最長有多久的線上數據不一致問題,這個緩存時間需要衡量自身的集群壓力以及業務接受的最大不一致時間。

2.3 拆key

? ? ? ? 如何既能保證不出現熱key問題,又能盡量的保證數據一致性呢?拆key也是一個好的解決方案。

? ? ? ? 我們在放入緩存時就將對應業務的緩存key拆分成多個不同的key。如下圖所示,我們首先在更新緩存的一側,將key拆成N份,比如一個key名字叫做”good_100″,那我們就可以把它拆成四份,”good_100_copy1″、”good_100_copy2″、”good_100_copy3″、”good_100_copy4″,每次更新和新增時都需要去改動這N個key,這一步就是拆key。

? ? ? ? 對于service端來講,我們就需要想辦法盡量將自己訪問的流量足夠的均勻,如何給自己即將訪問的熱key上加入后綴。幾種辦法,根據本機的ip或mac地址做hash,之后的值與拆key的數量做取余,最終決定拼接成什么樣的key后綴,從而打到哪臺機器上;服務啟動時的一個隨機數對拆key的數量做取余。

聊聊Redis中如何應對緩存熱key問題?常用方案分享

2.4 本地緩存的另外一種思路 配置中心

? ? ? ? 對于熟悉微服務配置中心的伙伴來講,我們的思路可以向配置中心的一致性轉變一下。拿nacos來舉例,它是如何做到分布式的配置一致性的,并且相應速度很快?那我們可以將緩存類比配置,這樣去做。

? ? ? ? 長輪詢+本地化的配置。首先服務啟動時會初始化全部的配置,然后定時啟動長輪詢去查詢當前服務監聽的配置有沒有變更,如果有變更,長輪詢的請求便會立刻返回,更新本地配置;如果沒有變更,對于所有的業務代碼都是使用本地的內存緩存配置。這樣就能保證分布式的緩存配置時效性與一致性。

2.5 其他可以提前做的預案

? ? ? ? 上面的每一個方案都相對獨立的去解決熱key問題,那么如果我們真的在面臨業務訴求時,其實會有很長的時間來考慮整體的方案設計。一些極端的秒殺場景帶來的熱key問題,如果我們預算充足,可以直接做服務的業務隔離、redis緩存集群的隔離,避免影響到正常業務的同時,也會可以臨時采取更好的容災、限流措施。

一些整合的方案

? ? ? ? 目前市面上已經有了不少關于hotKey相對完整的應用級解決方案,其中京東在這方面有開源的hotkey工具,原理就是在client端做洞察,然后上報對應hotkey,server端檢測到后,將對應hotkey下發到對應服務端做本地緩存,并且這個本地緩存在遠程對應的key更新后,會同步更新,已經是目前較為成熟的自動探測熱key、分布式一致性緩存解決方案,Redis視頻教程

聊聊Redis中如何應對緩存熱key問題?常用方案分享

總結

? ? ? ?

? 版權聲明
THE END
喜歡就支持一下吧
點贊8 分享