<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Redis的熱key隱患,探測它,干掉他

          共 5164字,需瀏覽 11分鐘

           ·

          2023-11-10 12:06

          做一些C端業(yè)務(wù),不可避免的要引入一級緩存來代替數(shù)據(jù)庫的壓力并且減少業(yè)務(wù)響應(yīng)時間,其實(shí)每次引入一個中間件來解決問題的同時,必然會帶來很多新的問題需要注意,比如緩存一致性問題。

          那么其實(shí)還會有一些其他問題比如使用Redis作為一級緩存時可能帶來的熱key、大key等問題,本文我們就熱key(hot key)問題來討論,如何合理的解決熱key問題。

          背景

          熱key是什么問題,如何導(dǎo)致的?

          一般來說,我們使用的緩存Redis都是多節(jié)點(diǎn)的集群版,對某個key進(jìn)行讀寫時,會根據(jù)該key的hash計算出對應(yīng)的slot,根據(jù)這個slot就能找到與之對應(yīng)的分片(一個master和多個slave組成的一組redis集群)來存取該K-V。但是在實(shí)際應(yīng)用過程中,對于某些特定業(yè)務(wù)或者一些特定的時段(比如電商業(yè)務(wù)的商品秒殺活動),可能會發(fā)生大量的請求訪問同一個key。

          所有的請求(且這類請求讀寫比例非常高)都會落到同一個redis server上,該redis的負(fù)載就會嚴(yán)重加劇,此時整個系統(tǒng)增加新redis實(shí)例也沒有任何用處,因為根據(jù)hash算法,同一個key的請求還是會落到同一臺新機(jī)器上,該機(jī)器依然會成為系統(tǒng)瓶頸2,甚至造成整個集群宕掉,若此熱點(diǎn)key的value 也比較大,也會造成網(wǎng)卡達(dá)到瓶頸,這種問題稱為 “熱key” 問題。

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

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

          1.熱key探測

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

          1.1 集群中每個slot的qps監(jiān)控

          熱key最明顯的影響是整個redis集群中的qps并沒有那么大的前提下,流量分布在集群中slot不均的問題,那么我們可以最先想到的就是對于每個slot中的流量做監(jiān)控,上報之后做每個slot的流量對比,就能在熱key出現(xiàn)時發(fā)現(xiàn)影響到的具體slot。雖然這個監(jiān)控最為方便,但是粒度過于粗了,關(guān)注工眾號:碼猿技術(shù)專欄,回復(fù)關(guān)鍵詞:1111 獲取阿里內(nèi)部Java性能調(diào)優(yōu)手冊!僅適用于前期集群監(jiān)控方案,并不適用于精準(zhǔn)探測到熱key的場景。

          1.2 proxy的代理機(jī)制作為整個流量入口統(tǒng)計

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

          1.3 redis基于LFU的熱點(diǎn)key發(fā)現(xiàn)機(jī)制

          redis 4.0以上的版本支持了每個節(jié)點(diǎn)上的基于LFU的熱點(diǎn)key發(fā)現(xiàn)機(jī)制,使用redis-cli –hotkeys即可,執(zhí)行redis-cli時加上–hotkeys選項。可以定時在節(jié)點(diǎn)中使用該命令來發(fā)現(xiàn)對應(yīng)熱點(diǎn)key。

          img

          如下所示,可以看到redis-cli –hotkeys的執(zhí)行結(jié)果,熱key的統(tǒng)計信息,這個命令的執(zhí)行時間較長,可以設(shè)置定時執(zhí)行來統(tǒng)計。

          1.4 基于Redis客戶端做探測

          由于redis的命令每次都是從客戶端發(fā)出,基于此我們可以在redis client的一些代碼處進(jìn)行統(tǒng)計計數(shù),每個client做基于時間滑動窗口的統(tǒng)計,超過一定的閾值之后上報至server,然后統(tǒng)一由server下發(fā)至各個client,并且配置對應(yīng)的過期時間。如何使用Redis實(shí)現(xiàn)電商系統(tǒng)的庫存扣減?

          這個方式看起來更優(yōu)美,其實(shí)在一些應(yīng)用場景中并不是那么合適,因為在client端這一側(cè)的改造,會給運(yùn)行的進(jìn)程帶來更大的內(nèi)存開銷,更直接的來說,對于Java和goLang這種自動內(nèi)存管理的語言,會更加頻繁的創(chuàng)建對象,從而觸發(fā)gc導(dǎo)致接口響應(yīng)耗時增加的問題,這個反而是不太容易預(yù)料到的事情。

          最終可以通過各個公司的基建,做出對應(yīng)的選擇。

          2.熱key解決

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

          2.1 對特定key或slot做限流

          一種最簡單粗暴的方式,對于特定的slot或者熱key做限流,這個方案明顯對于業(yè)務(wù)來說是有損的,所以建議只用在出現(xiàn)線上問題,需要止損的時候進(jìn)行特定的限流。redis常用命令和數(shù)據(jù)類型

          2.2 使用二級(本地)緩存

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

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

          //本地緩存獲取
          Object result = configCache.get(key);

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

          2.3 拆key

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

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

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

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

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

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

          2.5 其他可以提前做的預(yù)案

          上面的每一個方案都相對獨(dú)立的去解決熱key問題,那么如果我們真的在面臨業(yè)務(wù)訴求時,其實(shí)會有很長的時間來考慮整體的方案設(shè)計。一些極端的秒殺場景帶來的熱key問題,如果我們預(yù)算充足,可以直接做服務(wù)的業(yè)務(wù)隔離、redis緩存集群的隔離,避免影響到正常業(yè)務(wù)的同時,也會可以臨時采取更好的容災(zāi)、限流措施。細(xì)說 redis 十種數(shù)據(jù)類型及底層原理

          一些整合的方案

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

          總結(jié)

          以上就是筆者大概了解或?qū)嵺`過的的如何應(yīng)對熱key的一些方案,從發(fā)現(xiàn)熱key到解決熱key的兩個關(guān)鍵問題的應(yīng)對。每一個方案都有優(yōu)缺點(diǎn),比如會帶來業(yè)務(wù)的不一致性,實(shí)施起來較為困難等等,可以根據(jù)目前自身業(yè)務(wù)的特點(diǎn)、以及目前公司的基建去做對應(yīng)的調(diào)整和改變。

          推薦閱讀  點(diǎn)擊標(biāo)題可跳轉(zhuǎn)

          1、Redis 突然變慢了如何排查并解決?

          2、Redis 核心篇:唯快不破的秘密

          3、【面試官】如何解決Redis中出現(xiàn)的大key?

          瀏覽 203
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  天堂网在线视频免费观看 | 国产精品视频播放 | 看h片网站 | 亚洲搞搞 | 亚洲五月丁香免费 |