最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Redis緩存問題與緩存更新機制詳解

 更新時間:2025年01月20日 10:50:16   作者:夜夜流光相皎潔_小寧  
本文主要介紹了緩存問題及其解決方案,包括緩存穿透、緩存擊穿、緩存雪崩等問題的成因以及相應的預防和解決方法,同時,還詳細探討了緩存更新機制,包括不同情況下的緩存更新策略和內(nèi)存淘汰機制,并對比了它們的優(yōu)缺點

一、緩存問題

1.1 緩存穿透

1.1.1 問題來源

緩存穿透是指緩存和數(shù)據(jù)庫中都沒有的數(shù)據(jù),而用戶不斷發(fā)起請求。由于緩存是不命中時被動寫的,并且出于容錯考慮,如果從存儲層查不到數(shù)據(jù)則不寫入緩存,這將導致這個不存在的數(shù)據(jù)每次請求都要到存儲層去查詢,失去了緩存的意義。在流量大時,可能DB就掛掉了,要是有人利用不存在的key頻繁攻擊我們的應用,這就是漏洞。

1.1.2 解決方案

1.1.2.1 緩存空對象

  • 從緩存取不到的數(shù)據(jù),在數(shù)據(jù)庫中也沒有取到,這時也可以將key-value對寫為key-null,緩存有效時間可以設(shè)置短點,如30秒(設(shè)置太長會導致正常情況也沒法使用)。
  • 這樣可以防止攻擊用戶反復用同一個id暴力攻擊。

1.1.2.2 使用布隆過濾器

  • 類似于一個hash set,用于快速判某個元素是否存在于集合中,其典型的應用場景就是快速判斷一個key是否存在于某容器,不存在就直接返回。
  • 布隆過濾器的關(guān)鍵就在于hash算法和容器大小。

1.2 緩存擊穿

1.2.1 問題來源

緩存擊穿是指緩存某些熱點數(shù)據(jù)失效(一般是緩存時間到期),這時由于并發(fā)用戶特別多,同時讀緩存沒讀到數(shù)據(jù),又同時去數(shù)據(jù)庫去取數(shù)據(jù),引起數(shù)據(jù)庫壓力瞬間增大,造成過大壓力。

1.2.2 解決方案

1.2.2.1 設(shè)置熱點數(shù)據(jù)永遠不過期

可以在刷緩存時,設(shè)置熱點數(shù)據(jù)不過期。

1.2.2.2 新增后臺定時更新緩存線程(邏輯不過期)

后臺新增一個緩存更新線程,緩存快要過期前刷新緩存時間,防止緩存失效。

1.2.2.3 使用分布式互斥鎖

可以使用Redis提供的分布式互斥鎖,保證只有一個請求查詢數(shù)據(jù)庫和更新緩存,其他請求阻塞等待緩存更新完成后在訪問緩存。

1.2.2.4 接口限流與熔斷,降級

重要的接口一定要做好限流策略,防止用戶惡意刷接口,同時要降級準備,當接口中的某些服務(wù)不可用時候,進行熔斷,失敗快速返回機制。

1.3 緩存雪崩

1.3.1 問題來源

緩存雪崩是指Redis緩存不能正常提供服務(wù)了(阻塞、服務(wù)宕機、大面積緩存失效等造成),導致所有請求都落到了數(shù)據(jù)庫上,增加了數(shù)據(jù)庫壓力或者導致數(shù)據(jù)庫宕機。

1.3.2 解決方案

1.3.2.1 緩存過期時間隨機

緩存數(shù)據(jù)的過期時間設(shè)置隨機,防止同一時間大量數(shù)據(jù)過期現(xiàn)象發(fā)生。

1.3.2.2 分布式部署

采用分布式部署方式部署緩存,避免緩存服務(wù)單節(jié)點,同時將熱點數(shù)據(jù)均勻分布在不同的緩存數(shù)據(jù)庫中。

1.3.2.3 設(shè)置熱點數(shù)據(jù)永遠不過期

可以在刷緩存時,設(shè)置熱點數(shù)據(jù)不過期。

1.3.2.4 接口限流與熔斷,降級

重要的接口一定要做好限流策略,防止用戶惡意刷接口,同時要降級準備,當接口中的某些服務(wù)不可用時候,進行熔斷,失敗快速返回機制。

二、緩存更新機制

2.1 緩存更新策略分類

內(nèi)存淘汰超時剔除主動更新
說明重要的接口一定要做好限流策略,防止用戶惡意刷接口,同時要降級準備,當接口中的某些服務(wù)不可用時候,進行熔斷,失敗快速返回機制。給緩存數(shù)據(jù)添加TTL時間,到期后自動刪除緩存,下次查詢時更新緩存編寫業(yè)務(wù)邏輯,在修改數(shù)據(jù)的同時,更新緩存
一致性一般
維護成本

2.2 內(nèi)存淘汰機制

2.2.1 noeviction

不淘汰,這是默認的淘汰策略;

當內(nèi)存達到限制后,寫請求(set)會返回錯誤,讀請求(get)和刪除請求(del)可以繼續(xù)進行

2.2.2 volatile-lru

內(nèi)存不足時,在設(shè)置了過期時間的key中,優(yōu)先刪除最近最少使用的key

2.2.3 volatile-lfu

內(nèi)存不足時,在設(shè)置了過期時間的key中,優(yōu)先刪除使用頻率最少的key

2.2.4 volatile-ttl

內(nèi)存不足時,在設(shè)置了過期時間的key中,優(yōu)先刪除存活剩余時間最少的key

2.2.5 volatile-random

內(nèi)存不足時,在設(shè)置了過期時間的key中,隨機刪除某個key

2.2.6 allkey-lru

內(nèi)存不足時,在全體key范圍內(nèi),優(yōu)先刪除最近最少使用的key

2.2.7 allkey-lfu

內(nèi)存不足時,在全體key范圍內(nèi),優(yōu)先刪除使用頻率最少的key

2.2.8 allkey-random

內(nèi)存不足時,在全體key范圍內(nèi),隨機刪除某個key

2.3 超時剔除

2.3.1 定時刪除

設(shè)置一個定時任務(wù),隨機抽取部分過期時間的key,檢查是否過期,過期了就清除掉

2.3.2 惰性刪除

查詢獲取數(shù)據(jù)時,檢查緩存是否過期,過期則刪除,沒過期不刪除

Redis 默認采用惰性刪除+定時刪除結(jié)合的過期策略

2.4 主動更新

2.4.1 主動更新策略

2.4.1.1 Cache Aside Pattern

  • 由緩存的調(diào)用者
  • 在更新數(shù)據(jù)庫的同時更新緩存

2.4.1.2 Read/Write Through Pattern

  • 緩存和數(shù)據(jù)庫整合為一個服務(wù),由服務(wù)來維護一致性。
  • 調(diào)用者調(diào)用服務(wù),不用關(guān)心一致性問題。

2.4.1.3 Write Behind Caching Pattern

調(diào)用者只操作緩存,由其他線程異步的將緩存數(shù)據(jù)持久化到數(shù)據(jù)庫,最終保持一致。

在企業(yè)中使用最多的主動更新策略是 Cache Aside Pattern。也就是我們自己編碼來保證數(shù)據(jù)的一致性。

2.4.2 主動更新策略需要考慮的三個問題

2.4.1 刪除緩存還是更新緩存?

  • 2.4.1.1 刪除緩存

更新數(shù)據(jù)庫時讓緩存失效,查詢時再更新緩存。(延遲加載)一般選擇這個方案。

這個方案比較合理一點,可以避免過多的無效寫操作,緩存刪除后,只要沒人來查詢這條數(shù)據(jù),數(shù)據(jù)就不會被寫入緩存,這樣就可以避免大量無效的寫操作

  • 2.4.1.2 更新緩存

每次更新數(shù)據(jù)庫都更新緩存,無效寫操作比較多。

這種方式的缺點很明顯,舉個例子:假如我更新了100次數(shù)據(jù)庫,然后又同時更新了100次緩存,但是在更新的時候并沒有人來查這個數(shù)據(jù),那么我更新這100次緩存好像也沒啥用吧,相當于前99次都是無用功,只有最后一次才是有用的。這就是無效寫操作過多的原因。

2.4.2 如何保證緩存與數(shù)據(jù)庫的操作同時成功或失敗?

1)單體系統(tǒng),將緩存與數(shù)據(jù)庫操作放在一個事務(wù)中。

2)分布式系統(tǒng),利用TCC等分布式事務(wù)方案。

2.4.3 先操作緩存還是數(shù)據(jù)庫?

  • 2.4.3.1 先刪除緩存,再操作數(shù)據(jù)庫

這種方式存在很明顯的問題,假設(shè)有兩個并發(fā)操作,線程A更新,線程B查詢。線程A先刪除緩存,然后還沒來得及更新數(shù)據(jù)庫,CPU資源被線程B搶走,線程B查詢緩存發(fā)現(xiàn)沒有命中(因為已經(jīng)被線程A刪除了),查詢數(shù)據(jù)庫,然后把結(jié)果寫入到緩存中。這個時候線程A終于搶到CPU資源了,然后更新數(shù)據(jù)庫,此時就會造成數(shù)據(jù)不一致問題。

  • 2.4.3.2 先操作數(shù)據(jù)庫,再刪除緩存

這種處理方式使用的頻率是最高的,因為出錯的概率非常小,只有一種比較極端的情況才會出現(xiàn)數(shù)據(jù)一致性問題。

同樣有兩個并發(fā)請求,線程A查詢、線程B更新,當線程A查詢的時候,緩存剛好失效,然后就去查詢數(shù)據(jù)庫拿到數(shù)據(jù),在準備寫入緩存的時候,CPU資源被線程B搶走,線程B開始更新數(shù)據(jù)庫,然后刪除緩存(這一步其實等于無用,因為緩存已經(jīng)過期)。此時線程A再次獲取到CPU資源,然后寫入緩存,此時寫入的是更新前的舊數(shù)據(jù),會產(chǎn)生數(shù)據(jù)一致性問題。

看起來這確實也是一個問題,但是我們仔細分析一下這種情況都需要滿足哪些條件:

  • 1)并發(fā)讀寫操作
  • 2)讀緩存時,緩存剛好失效
  • 3)寫數(shù)據(jù)庫操作要比寫緩存快

寫數(shù)據(jù)庫是操作磁盤,寫緩存是操作內(nèi)存的,所以不太可能會出現(xiàn)寫磁盤的速度快于寫內(nèi)存的。因此使用這種方式出現(xiàn)數(shù)據(jù)一致性的概率是很小的。

  • 2.4.3.3 延時雙刪策略

延遲雙刪策略是分布式系統(tǒng)中數(shù)據(jù)庫存儲和緩存數(shù)據(jù)保持一致性的常用策略,但它不是強一致。其實不管哪種方案,都避免不了Redis存在臟數(shù)據(jù)的問題,只能減輕這個問題,要想徹底解決,得要用到同步鎖和對應的業(yè)務(wù)邏輯層面解決。

前面兩種方案的不足點我們進行了分析,第二種方式的使用頻率比較高,但是也有一些小缺陷,雖然說發(fā)生的概率很低,但是這個概率到了線上會不會發(fā)生也不好說,所以就有了延時雙刪策略對第二種方式做補充。

所謂延時雙刪就是先進行緩存清除,再執(zhí)行數(shù)據(jù)庫操作,最后(延遲N秒)再執(zhí)行緩存清除。延遲N秒的時間要大于一次寫操作的時間,這個延時N秒就是了完善保證第二種策略中不足,可以保證線程A的寫緩存和線程B的修改數(shù)據(jù)庫、刪除緩存都執(zhí)行完畢,然后再刪除緩存一次,就可以保證后面再來的查詢請求可以查詢到最新數(shù)據(jù)。

ps: 一般的延時時間設(shè)置為3S左右,具體情況要根據(jù)業(yè)務(wù)場景取最佳值。

2.5 緩存更新機制總結(jié)

  • 1)內(nèi)存淘汰:不用自己維護,利用Redis內(nèi)存淘汰機制,自動刪除部分緩存數(shù)據(jù),這些被刪除的數(shù)據(jù)在下一次被查詢時更新。這種方式一致性最差。
  • 2)超時剔除:給緩存數(shù)據(jù)加上過期時間 ,到期后自動刪除,下次查詢時更新,數(shù)據(jù)一致性問題大概率會出現(xiàn)。維護成本比較低。
  • 3)主動更新:編寫業(yè)務(wù)邏輯,在修改數(shù)據(jù)庫的同時更新緩存,一致性比較好,維護成本比較高。一般采用先操作數(shù)據(jù)庫再更新緩存的方式。

一般在數(shù)據(jù)一致性要求比較低的場景下可以使用內(nèi)存淘汰機制,比如商城首頁的分類信息,這些東西基本上是不會變化的。如果一致性要求比較高,我們可以采用主動更新+超時剔除兜底的方式來處理。

總結(jié)

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • redis和rabbitmq實現(xiàn)延時隊列的示例代碼

    redis和rabbitmq實現(xiàn)延時隊列的示例代碼

    在高并發(fā)場景下,延遲隊列顯得尤為重要,本文主要介紹了兩種方式,redis和rabbitmq實現(xiàn)延時隊列,具有一定的參考價值,感興趣的可以了解一下
    2024-03-03
  • redis?zset實現(xiàn)滑動窗口限流的代碼

    redis?zset實現(xiàn)滑動窗口限流的代碼

    這篇文章主要介紹了redis?zset實現(xiàn)滑動窗口限流,滑動窗口算法思想就是記錄一個滑動的時間窗口內(nèi)的操作次數(shù),操作次數(shù)超過閾值則進行限流,本文通過實例代碼給大家詳細介紹,需要的朋友參考下吧
    2022-03-03
  • Redis中l(wèi)ua腳本實現(xiàn)及其應用場景

    Redis中l(wèi)ua腳本實現(xiàn)及其應用場景

    本文主要介紹了Redis中l(wèi)ua腳本實現(xiàn)及其應用場景,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-04-04
  • redis主從+哨兵搭建的實現(xiàn)示例

    redis主從+哨兵搭建的實現(xiàn)示例

    本文主要介紹了redis主從+哨兵搭建的實現(xiàn)示例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2024-05-05
  • redis實現(xiàn)動態(tài)字符串SDS

    redis實現(xiàn)動態(tài)字符串SDS

    簡單動態(tài)字符串是Redis的基本數(shù)據(jù)結(jié)構(gòu)之一,用于存儲字符串和整型數(shù)據(jù),本文主要介紹了redis實現(xiàn)動態(tài)字符串SDS,具有一定的參考價值,感興趣的可以了解一下
    2024-04-04
  • redis刪除指定key的實現(xiàn)步驟

    redis刪除指定key的實現(xiàn)步驟

    本文主要介紹了redis刪除指定key的實現(xiàn)步驟,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2022-08-08
  • 如何提高Redis服務(wù)器的最大打開文件數(shù)限制

    如何提高Redis服務(wù)器的最大打開文件數(shù)限制

    文章討論了如何提高Redis服務(wù)器的最大打開文件數(shù)限制,以支持高并發(fā)服務(wù),本文給大家介紹的非常詳細,感興趣的朋友跟隨小編一起看看吧
    2025-01-01
  • Redis壓縮列表的設(shè)計與實現(xiàn)

    Redis壓縮列表的設(shè)計與實現(xiàn)

    壓縮列表(Ziplist)是 Redis 為了節(jié)省內(nèi)存而設(shè)計的一種緊湊型數(shù)據(jù)結(jié)構(gòu),主要用于存儲長度較短且數(shù)量較少的元素集合,本文給大家介紹了Redis壓縮列表的設(shè)計與實現(xiàn),文中通過代碼示例講解的非常詳細,需要的朋友可以參考下
    2024-08-08
  • 淺談redis加鎖常用幾種方式

    淺談redis加鎖常用幾種方式

    這篇文章主要介紹了淺談redis加鎖常用幾種方式,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-12-12
  • 一文帶你了解Redis怎么啟動以及使用

    一文帶你了解Redis怎么啟動以及使用

    對于Redis我們一般會使用到三種啟動方式:直接啟動、指定配置文件啟動、開機自啟動,下面這篇文章主要給大家介紹了關(guān)于Redis怎么啟動以及使用的相關(guān)資料,需要的朋友可以參考下
    2023-04-04

最新評論

汤阴县| 贺兰县| 称多县| 金门县| 喜德县| 达孜县| 手游| 任丘市| 甘南县| 乐安县| 叙永县| 高州市| 郁南县| 余干县| 渑池县| 江源县| 清河县| 临泽县| 万盛区| 射洪县| 兰溪市| 门头沟区| 威信县| 曲松县| 西昌市| 塔河县| 洛南县| 长葛市| 鲜城| 砚山县| 吉安县| 松桃| 六枝特区| 宁陵县| 房山区| 星子县| 收藏| 新余市| 宣汉县| 昌平区| 胶南市|