日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

Redis缓存雪崩、缓存穿透、热点Key解决方案和分析

發(fā)布時間:2024/2/28 数据库 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Redis缓存雪崩、缓存穿透、热点Key解决方案和分析 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

轉載自??https://blog.csdn.net/wang0112233/article/details/79558612

https://www.sohu.com/a/230787856_231667

今天又學到了很多,感覺雪崩和穿透很有意思理解起來也比較清晰,然后我搜索了一些資料,給自己做一個普及

我們通常使用?緩存 + 過期時間的策略來幫助我們加速接口的訪問速度,減少了后端負載,同時保證功能的更新

?

?

緩存穿透

緩存系統(tǒng),按照KEY去查詢VALUE,當KEY對應的VALUE一定不存在的時候并對KEY并發(fā)請求量很大的時候,就會對后端造成很大的壓力。

(查詢一個必然不存在的數(shù)據(jù)。比如文章表,查詢一個不存在的id,每次都會訪問DB,如果有人惡意破壞,很可能直接對DB造成影響。)

由于緩存不命中,每次都要查詢持久層。從而失去緩存的意義。

?

解決方法:

1、緩存層緩存空值。?
–緩存太多空值,占用更多空間。(優(yōu)化:給個空值過期時間)?
–存儲層更新代碼了,緩存層還是空值。(優(yōu)化:后臺設置時主動刪除空值,并緩存把值進去)

2、將數(shù)據(jù)庫中所有的查詢條件,放到布隆過濾器中。當一個查詢請求來臨的時候,先經(jīng)過布隆過濾器進行檢查,如果請求存在這個條件中,那么繼續(xù)執(zhí)行,如果不在,直接丟棄。

?

備注:

? ? 比如數(shù)據(jù)庫中有10000個條件,那么布隆過濾器的容量size設置的要稍微比10000大一些,比如12000.

? ? 對于誤判率的設置,根據(jù)實際項目,以及硬件設施來具體決定。但是一定不能設置為0,并且誤判率設置的越小,哈希函數(shù)跟數(shù)組長度都會更多跟更長,那么對硬件,內存中間的要求就會相應的高。

??private static?BloomFilter<Integer>?bloomFilter?=?BloomFilter.create(Funnels.integerFunnel(),?size,?0.0001);?

? ? 有了size跟誤判率,那么布隆過濾器就會產(chǎn)生相應的哈希函數(shù)跟數(shù)組。

? ? 綜上:我們可以利用布隆過濾器,將redis緩存擊穿控制在一個可容忍的范圍內。

?


緩存雪崩(緩存失效)

????????如果緩存集中在一段時間內失效,發(fā)生大量的緩存穿透,所有的查詢都落在數(shù)據(jù)庫上,造成了緩存雪崩。

????????緩存層宕掉后,流量會像奔逃的野牛一樣,打向后端存儲

? ? 解決方法:

  • 在緩存失效后,通過加鎖或者隊列來控制讀數(shù)據(jù)庫寫緩存的線程數(shù)量。比如對某個key只允許一個線程查詢數(shù)據(jù)和寫緩存,其他線程等待。
  • 可以通過緩存reload機制,預先去更新緩存,再即將發(fā)生大并發(fā)訪問前手動觸發(fā)加載緩存
  • 不同的key,設置不同的過期時間,讓緩存失效的時間點盡量均勻
  • 做二級緩存,或者雙緩存策略。A1為原始緩存,A2為拷貝緩存,A1失效時,可以訪問A2,A1緩存失效時間設置為短期,A2設置為長期。
  • ?

    ?

    熱點key

    ? ????(1) 這個key是一個熱點key(例如一個重要的新聞,一個熱門的八卦新聞等等),所以這種key訪問量可能非常大。

    ? ? ? (2) 緩存的構建是需要一定時間的。(可能是一個復雜計算,例如復雜的sql、多次IO、多個依賴(各種接口)等等)

    ? ? ? ?于是就會出現(xiàn)一個致命問題:在緩存失效的瞬間,有大量線程來構建緩存(見下圖),造成后端負載加大,甚至可能會讓系統(tǒng)崩潰?。

    ????解決方法:

    1. 使用互斥鎖(mutex key):這種解決方案思路比較簡單,就是只讓一個線程構建緩存,其他線程等待構建緩存的線程執(zhí)行完,重新從緩存獲取數(shù)據(jù)就可以了

    2. "提前"使用互斥鎖(mutex key):在value內部設置1個超時值(timeout1), timeout1比實際的memcache timeout(timeout2)小。當從cache讀取到timeout1發(fā)現(xiàn)它已經(jīng)過期時候,馬上延長timeout1并重新設置到cache。然后再從數(shù)據(jù)庫加載數(shù)據(jù)并設置到cache中。

    3. "永遠不過期":

    ?這里的“永遠不過期”包含兩層意思:

    ? ? (1) 從redis上看,確實沒有設置過期時間,這就保證了,不會出現(xiàn)熱點key過期問題,也就是“物理”不過期。

    ? ? (2) 從功能上看,如果不過期,那不就成靜態(tài)的了嗎?所以我們把過期時間存在key對應的value里,如果發(fā)現(xiàn)要過期了,通過一個后臺的異步線程進行緩存的構建,也就是“邏輯”過期

    4. 資源保護:可以做資源的隔離保護主線程池,如果把這個應用到緩存的構建也未嘗不可。

    四種方案對比:

    ? ? ? 作為一個并發(fā)量較大的互聯(lián)網(wǎng)應用,我們的目標有3個:

    ? ? ? 1. 加快用戶訪問速度,提高用戶體驗。

    ? ? ? 2. 降低后端負載,保證系統(tǒng)平穩(wěn)。

    ? ? ? 3. 保證數(shù)據(jù)“盡可能”及時更新(要不要完全一致,取決于業(yè)務,而不是技術。)

    ? ? ? 所以第二節(jié)中提到的四種方法,可以做如下比較,還是那就話:沒有最好,只有最合適。?

    解決方案優(yōu)點缺點
    簡單分布式鎖(Tim yang)

    ?1. 思路簡單

    2. 保證一致性

    1. 代碼復雜度增大

    2. 存在死鎖的風險

    3. 存在線程池阻塞的風險

    加另外一個過期時間(Tim yang)?1. 保證一致性同上?
    不過期(本文)

    1. 異步構建緩存,不會阻塞線程池

    1. 不保證一致性。

    2. 代碼復雜度增大(每個value都要維護一個timekey)。

    3. 占用一定的內存空間(每個value都要維護一個timekey)。

    資源隔離組件hystrix(本文)

    1. hystrix技術成熟,有效保證后端。

    2. hystrix監(jiān)控強大。

    ?

    ?

    1. 部分訪問存在降級策略。?


    總結

    ?

    ? ?1. ?熱點key + 過期時間 + 復雜的構建緩存過程 => mutex key問題

    ? ?2.?構建緩存一個線程做就可以了。

    ? ?3. 四種解決方案:沒有最佳只有最合適。

    ?

    參考文獻:

    擊穿/穿透:http://blog.csdn.net/kl1106/article/details/79478901

    雪崩:http://blog.csdn.net/qq_36858183/article/details/78424690

    熱點key:http://carlosfu.iteye.com/blog/2269678‘

    =========================================================================

    今天我簡單的跟大家介紹一下關于Redis中緩存雪崩、緩存穿透、緩存預熱、緩存更新、緩存降級等概念的入門及簡單解決方案。由于水平有限,如果發(fā)現(xiàn)以上文章有錯誤或者需要改進的地方請大家指出,萬分感謝!!!

    一、緩存雪崩通俗簡單的理解就是:由于原有緩存失效(或者數(shù)據(jù)未加載到緩存中),新緩存未到期間(緩存正常從Redis中獲取,如下圖)所有原本應該訪問緩存的請求都去查詢數(shù)據(jù)庫了,而對數(shù)據(jù)庫CPU和內存造成巨大壓力,嚴重的會造成數(shù)據(jù)庫宕機,造成系統(tǒng)的崩潰。

    緩存失效的時候如下圖:

    緩存失效時的雪崩效應對底層系統(tǒng)的沖擊非常可怕!那有什么辦法來解決這個問題呢?基本解決思路如下:

    第一,大多數(shù)系統(tǒng)設計者考慮用加鎖或者隊列的方式保證來保證不會有大量的線程對數(shù)據(jù)庫一次性進行讀寫,避免緩存失效時對數(shù)據(jù)庫造成太大的壓力,雖然能夠在一定的程度上緩解了數(shù)據(jù)庫的壓力但是與此同時又降低了系統(tǒng)的吞吐量。

    第二,分析用戶的行為,盡量讓緩存失效的時間均勻分布。

    第三,如果是因為某臺緩存服務器宕機,可以考慮做主備,比如:redis主備,但是雙緩存涉及到更新事務的問題,update可能讀到臟數(shù)據(jù),需要好好解決。

    以下簡單介紹兩種實現(xiàn)方式的偽代碼:

    (1)碰到這種情況,一般并發(fā)量不是特別多的時候,使用最多的解決方案是加鎖排隊,偽代碼如下:

    加鎖排隊只是為了減輕數(shù)據(jù)庫的壓力,并沒有提高系統(tǒng)吞吐量。假設在高并發(fā)下,緩存重建期間key是鎖著的,這是過來1000個請求999個都在阻塞的。同樣會導致用戶等待超時,這是個治標不治本的方法!

    注意:加鎖排隊的解決方式分布式環(huán)境的并發(fā)問題,有可能還要解決分布式鎖的問題;線程還會被阻塞,用戶體驗很差!因此,在真正的高并發(fā)場景下很少使用!

    (2)還有一個解決辦法解決方案是:給每一個緩存數(shù)據(jù)增加相應的緩存標記,記錄緩存的是否失效,如果緩存標記失效,則更新數(shù)據(jù)緩存,實例偽代碼如

    下:

    解釋說明:

    1、緩存標記:記錄緩存數(shù)據(jù)是否過期,如果過期會觸發(fā)通知另外的線程在后臺去更新實際key的緩存;

    2、緩存數(shù)據(jù):它的過期時間比緩存標記的時間延長1倍,例:標記緩存時間30分鐘,數(shù)據(jù)緩存設置為60分鐘。 這樣,當緩存標記key過期后,實際緩存還能把舊數(shù)據(jù)返回給調用端,直到另外的線程在后臺更新完成后,才會返回新緩存。

    關于緩存崩潰的解決方法,這里提出了三種方案:使用鎖或隊列、設置過期標志更新緩存、為key設置不同的緩存失效時間,還有一各被稱為“二級緩存”的解決方法,有興趣的讀者可以自行研究。

    二、緩存穿透

    緩存穿透是指用戶查詢數(shù)據(jù),在數(shù)據(jù)庫沒有,自然在緩存中也不會有。這樣就導致用戶查詢的時候,在緩存中找不到,每次都要去數(shù)據(jù)庫中查詢。

    解決思路:

    1,如果查詢數(shù)據(jù)庫也為空,直接設置一個默認值存放到緩存,這樣第二次到緩沖中獲取就有值了,而不會繼續(xù)訪問數(shù)據(jù)庫,這種辦法最簡單粗暴。

    2,根據(jù)緩存數(shù)據(jù)Key的規(guī)則。例如我們公司是做機頂盒的,緩存數(shù)據(jù)以Mac為Key,Mac是有規(guī)則,如果不符合規(guī)則就過濾掉,這樣可以過濾一部分查詢。在做緩存規(guī)劃的時候,Key有一定規(guī)則的話,可以采取這種辦法。這種辦法只能緩解一部分的壓力,過濾和系統(tǒng)無關的查詢,但是無法根治。

    3,采用布隆過濾器,將所有可能存在的數(shù)據(jù)哈希到一個足夠大的BitSet中,不存在的數(shù)據(jù)將會被攔截掉,從而避免了對底層存儲系統(tǒng)的查詢壓力。關于布隆過濾器,詳情查看:基于BitSet的布隆過濾器(Bloom Filter)

    大并發(fā)的緩存穿透會導致緩存雪崩。

    把空結果,也給緩存起來,這樣下次同樣的請求就可以直接返回空了,即可以避免當查詢的值為空時引起的緩存穿透。同時也可以單獨設置個緩存區(qū)域存儲空值,對要查詢的key進行預先校驗,然后再放行給后面的正常緩存處理邏輯。

    三、緩存預熱

    緩存預熱這個應該是一個比較常見的概念,相信很多小伙伴都應該可以很容易的理解,緩存預熱就是系統(tǒng)上線后,將相關的緩存數(shù)據(jù)直接加載到緩存系統(tǒng)。這樣就可以避免在用戶請求的時候,先查詢數(shù)據(jù)庫,然后再將數(shù)據(jù)緩存的問題!用戶直接查詢事先被預熱的緩存數(shù)據(jù)!

    解決思路:

    1、直接寫個緩存刷新頁面,上線時手工操作下;

    2、數(shù)據(jù)量不大,可以在項目啟動的時候自動進行加載;

    3、定時刷新緩存;

    四、緩存更新

    除了緩存服務器自帶的緩存失效策略之外(Redis默認的有6中策略可供選擇),我們還可以根據(jù)具體的業(yè)務需求進行自定義的緩存淘汰,常見的策略有兩種:

    (1)定時去清理過期的緩存;

    (2)當有用戶請求過來時,再判斷這個請求所用到的緩存是否過期,過期的話就去底層系統(tǒng)得到新數(shù)據(jù)并更新緩存。

    兩者各有優(yōu)劣,第一種的缺點是維護大量緩存的key是比較麻煩的,第二種的缺點就是每次用戶請求過來都要判斷緩存失效,邏輯相對比較復雜!具體用哪種方案,大家可以根據(jù)自己的應用場景來權衡。

    五、緩存降級

    當訪問量劇增、服務出現(xiàn)問題(如響應時間慢或不響應)或非核心服務影響到核心流程的性能時,仍然需要保證服務還是可用的,即使是有損服務。系統(tǒng)可以根據(jù)一些關鍵數(shù)據(jù)進行自動降級,也可以配置開關實現(xiàn)人工降級。

    降級的最終目的是保證核心服務可用,即使是有損的。而且有些服務是無法降級的(如加入購物車、結算)。

    在進行降級之前要對系統(tǒng)進行梳理,看看系統(tǒng)是不是可以丟卒保帥;從而梳理出哪些必須誓死保護,哪些可降級;比如可以參考日志級別設置預案:

    (1)一般:比如有些服務偶爾因為網(wǎng)絡抖動或者服務正在上線而超時,可以自動降級;

    (2)警告:有些服務在一段時間內成功率有波動(如在95~100%之間),可以自動降級或人工降級,并發(fā)送告警;

    (3)錯誤:比如可用率低于90%,或者數(shù)據(jù)庫連接池被打爆了,或者訪問量突然猛增到系統(tǒng)能承受的最大閥值,此時可以根據(jù)情況自動降級或者人工降級;

    (4)嚴重錯誤:比如因為特殊原因數(shù)據(jù)錯誤了,此時需要緊急人工降級。

    另外,我想補充一些知識點

    分布式緩存系統(tǒng)面臨的問題緩存一致性問題

    1:緩存系統(tǒng)與底層數(shù)據(jù)的一致性。這點在底層系統(tǒng)是“可讀可寫”時,寫得尤為重要

    2:有繼承關系的緩存之間的一致性。為了盡量提高緩存命中率,緩存也是分層:全局緩存,二級緩存。他們是存在繼承關系的。全局緩存可以有二級緩存來組成。

    3:多個緩存副本之間的一致性。為了保證系統(tǒng)的高可用性,緩存系統(tǒng)背后往往會接兩套存儲系統(tǒng)(如memcache,redis等)

    緩存穿透和緩存雪崩

    上面有講述。

    緩存數(shù)據(jù)的淘汰

    緩存淘汰的策略有兩種: (1) 定時去清理過期的緩存。 (2)當有用戶請求過來時,再判斷這個請求所用到的緩存是否過期,過期的話就去底層系統(tǒng)得到新數(shù)據(jù)并更新緩存。 兩者各有優(yōu)劣,第一種的缺點是維護大量緩存的key是比較麻煩的,第二種的缺點就是每次用戶請求過來都要判斷緩存失效,邏輯相對比較復雜,具體用哪種方案,大家可以根據(jù)自己的應用場景來權衡。 1. 預估失效時間 2. 版本號(必須單調遞增,時間戳是最好的選擇)3. 提供手動清理緩存的接口。

    緩存算法

    FIFO算法:First in First out,先進先出。原則:一個數(shù)據(jù)最先進入緩存中,則應該最早淘汰掉。也就是說,當緩存滿的時候,應當把最先進入緩存的數(shù)據(jù)給淘汰掉。

    LFU算法:Least Frequently Used,最不經(jīng)常使用算法。

    LRU算法:Least Recently Used,近期最少使用算法。請查看:Memcached之你真正理解LRU嗎(4)

    LRU和LFU的區(qū)別。LFU算法是根據(jù)在一段時間里數(shù)據(jù)項被使用的次數(shù)選擇出最少使用的數(shù)據(jù)項,即根據(jù)使用次數(shù)的差異來決定。而LRU是根據(jù)使用時間的差異來決定的

    總結

    以上是生活随笔為你收集整理的Redis缓存雪崩、缓存穿透、热点Key解决方案和分析的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內容還不錯,歡迎將生活随笔推薦給好友。