天天看點

緩存擊穿、緩存穿透、緩存雪崩介紹及解決思路

背景

在現代軟體架構中,緩存的應用已經非常普及。緩存的使用在面試和實踐中都是避不開的硬技能、硬知識,如果你說還不太熟悉緩存的使用,可能都不好意思說自己是程式員。

這篇文章,帶大家進一步學習在緩存使用中不得不考慮三個特殊場景:緩存穿透、緩存雪崩、緩存擊穿。

為什麼說不得不考慮?因為如果不考慮這些特殊的場景,在高并發的情況可能直接導緻系統崩潰。下面以常見的Redis緩存元件為例來講解這三種場景及解決方案。

大前提

當我們使用緩存時,目标通常有兩個:第一,提升響應效率和并發量;第二,減輕資料庫的壓力。

而本文中所提到的這三種場景:緩存穿透、緩存雪崩和緩存擊穿的發生,都是因為在某些特殊情況下,緩存失去了預期的功能所緻。

當緩存失效或沒有抵擋住流量,流量直接湧入到資料庫,在高并發的情況下,可能直接擊垮資料庫,導緻整個系統崩潰。

這就是我們需要知道的大前提,而緩存穿透、緩存雪崩和緩存擊穿,隻不過是在這個大前提下的不同場景的細分場景而已。

緩存穿透

大多數情況,緩存可以減少資料庫的查詢,提升系統性能。

通常流程是:一個請求過來,先查詢是否在緩存當中,如果緩存中存在,則直接傳回。如果緩存中不存在對應的資料,則檢索資料庫,如果資料庫中存在對應的資料,則更新緩存并傳回結果。如果資料庫中也不存在對應的資料,則傳回空或錯誤。

緩存穿透(cache penetration)是使用者通路的資料既不在緩存當中,也不在資料庫中。出于容錯的考慮,如果從底層資料庫查詢不到資料,則不寫入緩存。這就導緻每次請求都會到底層資料庫進行查詢,緩存也失去了意義。當高并發或有人利用不存在的Key頻繁攻擊時,資料庫的壓力驟增,甚至崩潰,這就是緩存穿透問題。

緩存擊穿、緩存穿透、緩存雪崩介紹及解決思路

緩存穿透

緩存穿透發生的場景一般有兩類:

  • 原來資料是存在的,但由于某些原因(誤删除、主動清理等)在緩存和資料庫層面被删除了,但前端或前置的應用程式依舊保有這些資料;
  • 惡意攻擊行為,利用不存在的Key或者惡意嘗試導緻産生大量不存在的業務資料請求。

緩存穿透通常有四種解決方案,我們逐一介紹分析。

方案一:緩存空值(null)或預設值

分析業務請求,如果是正常業務請求時發生緩存穿透現象,可針對相應的業務資料,在資料庫查詢不存在時,将其緩存為空值(null)或預設值。需要注意的是,針對空值的緩存失效時間不宜過長,一般設定為5分鐘之内。當資料庫被寫入或更新該key的新資料時,緩存必須同時被重新整理,避免資料不一緻。

方案二:業務邏輯前置校驗

在業務請求的入口處進行資料合法性校驗,檢查請求參數是否合理、是否包含非法值、是否惡意請求等,提前有效阻斷非法請求。比如,根據年齡查詢時,請求的年齡為-10歲,這顯然是不合法的請求參數,直接在參數校驗時進行判斷傳回。

方案三:使用布隆過濾器請求白名單

在寫入資料時,使用布隆過濾器進行标記(相當于設定白名單),業務請求發現緩存中無對應資料時,可先通過查詢布隆過濾器判斷資料是否在白名單内,如果不在白名單内,則直接傳回空或失敗。

方案四:使用者黑名單限制

當發生異常情況時,實時監控通路的對象和資料,分析使用者行為,針對故意請求、爬蟲或攻擊者,進行特定使用者的限制;

當然,可能針對緩存穿透的情況,也有可能是其他的原因引起,可以針對具體情況,采用對應的措施。

緩存雪崩

在使用緩存時,通常會對緩存設定過期時間,一方面目的是保持緩存與資料庫資料的一緻性,另一方面是減少冷緩存占用過多的記憶體空間。

但當緩存中大量熱點緩存采用了相同的實效時間,就會導緻緩存在某一個時刻同時實效,請求全部轉發到資料庫,進而導緻資料庫壓力驟增,甚至當機。進而形成一系列的連鎖反應,造成系統崩潰等情況,這就是緩存雪崩(Cache Avalanche)。

緩存擊穿、緩存穿透、緩存雪崩介紹及解決思路

緩存雪崩

上面講到的是熱點key同時失效的場景,另外就是由于某些原因導緻緩存服務當機、挂掉或不響應,也同樣會導緻流量直接轉移到資料庫。

是以,緩存雪崩的場景通常有兩個:

  • 大量熱點key同時過期;
  • 緩存服務故障;

緩存雪崩的解決方案:

  • 通常的解決方案是将key的過期時間後面加上一個

    随機數

    (比如随機1-5分鐘),讓key均勻的失效。
  • 考慮用隊列或者鎖的方式,保證緩存單線程寫,但這種方案可能會影響并發量。
  • 熱點資料可以考慮不失效,背景異步更新緩存,适用于不嚴格要求緩存一緻性的場景。
  • 雙key政策,主key設定過期時間,備key不設定過期時間,當主key失效時,直接傳回備key值。
  • 建構緩存高可用叢集(針對緩存服務故障情況)。
  • 當緩存雪崩發生時,服務熔斷、限流、降級等措施保障。

緩存擊穿

緩存雪崩是指隻大量熱點key同時失效的情況,如果是單個熱點key,在不停的扛着大并發,在這個key失效的瞬間,持續的大并發請求就會擊破緩存,直接請求到資料庫,好像蠻力擊穿一樣。這種情況就是緩存擊穿(Cache Breakdown)。

緩存擊穿、緩存穿透、緩存雪崩介紹及解決思路

緩存擊穿

從定義上可以看出,緩存擊穿和緩存雪崩很類似,隻不過是緩存擊穿是一個熱點key失效,而緩存雪崩是大量熱點key失效。是以,可以将緩存擊穿看作是緩存雪崩的一個子集。

緩存擊穿的解決方案:

  • 使用互斥鎖(Mutex Key),隻讓一個線程建構緩存,其他線程等待建構緩存執行完畢,重新從緩存中擷取資料。單機通過synchronized或lock來處理,分布式環境采用分布式鎖。
  • 熱點資料不設定過期時間,背景異步更新緩存,适用于不嚴格要求緩存一緻性的場景。
  • ”提前“使用互斥鎖(Mutex Key):在value内部設定一個比緩存(Redis)過期時間短的過期時間辨別,當異步線程發現該值快過期時,馬上延長内置的這個時間,并重新從資料庫加載資料,設定到緩存中去。

小結

本文介紹了在使用緩存時經常會遇到的三種異常情況:緩存穿透、緩存雪崩和緩存擊穿。

三種異常情況從根本上來說都是因為本應該通路緩存的,但是緩存不存在或服務異常,導緻流量直接進入了資料庫層面。

其中緩存雪崩和緩存擊穿是因為資料不存在(或服務異常擷取不到),導緻大量請求通路資料庫,進而導緻資料庫壓力驟增,甚至崩潰。

而緩存穿透則是由于資料本身就不存在,導緻緩存沒有進行資料緩存,流量進入資料庫層。

針對不同的緩存異常場景,可選擇不同的方案來進行處理。當然,除了上述方案,我們還可以限流、降級、熔斷等服務層的措施,也可以考慮資料庫層是否可以進行橫向擴充,當緩存異常發生時,確定資料庫能夠抗住流量,不至于讓整個系統崩潰。

背景

在現代軟體架構中,緩存的應用已經非常普及。緩存的使用在面試和實踐中都是避不開的硬技能、硬知識,如果你說還不太熟悉緩存的使用,可能都不好意思說自己是程式員。

這篇文章,帶大家進一步學習在緩存使用中不得不考慮三個特殊場景:緩存穿透、緩存雪崩、緩存擊穿。

為什麼說不得不考慮?因為如果不考慮這些特殊的場景,在高并發的情況可能直接導緻系統崩潰。下面以常見的Redis緩存元件為例來講解這三種場景及解決方案。

大前提

當我們使用緩存時,目标通常有兩個:第一,提升響應效率和并發量;第二,減輕資料庫的壓力。

而本文中所提到的這三種場景:緩存穿透、緩存雪崩和緩存擊穿的發生,都是因為在某些特殊情況下,緩存失去了預期的功能所緻。

當緩存失效或沒有抵擋住流量,流量直接湧入到資料庫,在高并發的情況下,可能直接擊垮資料庫,導緻整個系統崩潰。

這就是我們需要知道的大前提,而緩存穿透、緩存雪崩和緩存擊穿,隻不過是在這個大前提下的不同場景的細分場景而已。

緩存穿透

大多數情況,緩存可以減少資料庫的查詢,提升系統性能。

通常流程是:一個請求過來,先查詢是否在緩存當中,如果緩存中存在,則直接傳回。如果緩存中不存在對應的資料,則檢索資料庫,如果資料庫中存在對應的資料,則更新緩存并傳回結果。如果資料庫中也不存在對應的資料,則傳回空或錯誤。

緩存穿透(cache penetration)是使用者通路的資料既不在緩存當中,也不在資料庫中。出于容錯的考慮,如果從底層資料庫查詢不到資料,則不寫入緩存。這就導緻每次請求都會到底層資料庫進行查詢,緩存也失去了意義。當高并發或有人利用不存在的Key頻繁攻擊時,資料庫的壓力驟增,甚至崩潰,這就是緩存穿透問題。

緩存擊穿、緩存穿透、緩存雪崩介紹及解決思路

緩存穿透

緩存穿透發生的場景一般有兩類:

  • 原來資料是存在的,但由于某些原因(誤删除、主動清理等)在緩存和資料庫層面被删除了,但前端或前置的應用程式依舊保有這些資料;
  • 惡意攻擊行為,利用不存在的Key或者惡意嘗試導緻産生大量不存在的業務資料請求。

緩存穿透通常有四種解決方案,我們逐一介紹分析。

方案一:緩存空值(null)或預設值

分析業務請求,如果是正常業務請求時發生緩存穿透現象,可針對相應的業務資料,在資料庫查詢不存在時,将其緩存為空值(null)或預設值。需要注意的是,針對空值的緩存失效時間不宜過長,一般設定為5分鐘之内。當資料庫被寫入或更新該key的新資料時,緩存必須同時被重新整理,避免資料不一緻。

方案二:業務邏輯前置校驗

在業務請求的入口處進行資料合法性校驗,檢查請求參數是否合理、是否包含非法值、是否惡意請求等,提前有效阻斷非法請求。比如,根據年齡查詢時,請求的年齡為-10歲,這顯然是不合法的請求參數,直接在參數校驗時進行判斷傳回。

方案三:使用布隆過濾器請求白名單

在寫入資料時,使用布隆過濾器進行标記(相當于設定白名單),業務請求發現緩存中無對應資料時,可先通過查詢布隆過濾器判斷資料是否在白名單内,如果不在白名單内,則直接傳回空或失敗。

方案四:使用者黑名單限制

當發生異常情況時,實時監控通路的對象和資料,分析使用者行為,針對故意請求、爬蟲或攻擊者,進行特定使用者的限制;

當然,可能針對緩存穿透的情況,也有可能是其他的原因引起,可以針對具體情況,采用對應的措施。

緩存雪崩

在使用緩存時,通常會對緩存設定過期時間,一方面目的是保持緩存與資料庫資料的一緻性,另一方面是減少冷緩存占用過多的記憶體空間。

但當緩存中大量熱點緩存采用了相同的實效時間,就會導緻緩存在某一個時刻同時實效,請求全部轉發到資料庫,進而導緻資料庫壓力驟增,甚至當機。進而形成一系列的連鎖反應,造成系統崩潰等情況,這就是緩存雪崩(Cache Avalanche)。

緩存擊穿、緩存穿透、緩存雪崩介紹及解決思路

緩存雪崩

上面講到的是熱點key同時失效的場景,另外就是由于某些原因導緻緩存服務當機、挂掉或不響應,也同樣會導緻流量直接轉移到資料庫。

是以,緩存雪崩的場景通常有兩個:

  • 大量熱點key同時過期;
  • 緩存服務故障;

緩存雪崩的解決方案:

  • 通常的解決方案是将key的過期時間後面加上一個

    随機數

    (比如随機1-5分鐘),讓key均勻的失效。
  • 考慮用隊列或者鎖的方式,保證緩存單線程寫,但這種方案可能會影響并發量。
  • 熱點資料可以考慮不失效,背景異步更新緩存,适用于不嚴格要求緩存一緻性的場景。
  • 雙key政策,主key設定過期時間,備key不設定過期時間,當主key失效時,直接傳回備key值。
  • 建構緩存高可用叢集(針對緩存服務故障情況)。
  • 當緩存雪崩發生時,服務熔斷、限流、降級等措施保障。

緩存擊穿

緩存雪崩是指隻大量熱點key同時失效的情況,如果是單個熱點key,在不停的扛着大并發,在這個key失效的瞬間,持續的大并發請求就會擊破緩存,直接請求到資料庫,好像蠻力擊穿一樣。這種情況就是緩存擊穿(Cache Breakdown)。

緩存擊穿、緩存穿透、緩存雪崩介紹及解決思路

緩存擊穿

從定義上可以看出,緩存擊穿和緩存雪崩很類似,隻不過是緩存擊穿是一個熱點key失效,而緩存雪崩是大量熱點key失效。是以,可以将緩存擊穿看作是緩存雪崩的一個子集。

緩存擊穿的解決方案:

  • 使用互斥鎖(Mutex Key),隻讓一個線程建構緩存,其他線程等待建構緩存執行完畢,重新從緩存中擷取資料。單機通過synchronized或lock來處理,分布式環境采用分布式鎖。
  • 熱點資料不設定過期時間,背景異步更新緩存,适用于不嚴格要求緩存一緻性的場景。
  • ”提前“使用互斥鎖(Mutex Key):在value内部設定一個比緩存(Redis)過期時間短的過期時間辨別,當異步線程發現該值快過期時,馬上延長内置的這個時間,并重新從資料庫加載資料,設定到緩存中去。

小結

本文介紹了在使用緩存時經常會遇到的三種異常情況:緩存穿透、緩存雪崩和緩存擊穿。

三種異常情況從根本上來說都是因為本應該通路緩存的,但是緩存不存在或服務異常,導緻流量直接進入了資料庫層面。

其中緩存雪崩和緩存擊穿是因為資料不存在(或服務異常擷取不到),導緻大量請求通路資料庫,進而導緻資料庫壓力驟增,甚至崩潰。

而緩存穿透則是由于資料本身就不存在,導緻緩存沒有進行資料緩存,流量進入資料庫層。

針對不同的緩存異常場景,可選擇不同的方案來進行處理。當然,除了上述方案,我們還可以限流、降級、熔斷等服務層的措施,也可以考慮資料庫層是否可以進行橫向擴充,當緩存異常發生時,確定資料庫能夠抗住流量,不至于讓整個系統崩潰。

————————————————

版權聲明:本文為CSDN部落客「夢遠星帆」的原創文章,遵循CC 4.0 BY-SA版權協定,轉載請附上原文出處連結及本聲明。

原文連結:https://blog.csdn.net/qq_45637260/article/details/125866738

背景

在現代軟體架構中,緩存的應用已經非常普及。緩存的使用在面試和實踐中都是避不開的硬技能、硬知識,如果你說還不太熟悉緩存的使用,可能都不好意思說自己是程式員。

這篇文章,帶大家進一步學習在緩存使用中不得不考慮三個特殊場景:緩存穿透、緩存雪崩、緩存擊穿。

為什麼說不得不考慮?因為如果不考慮這些特殊的場景,在高并發的情況可能直接導緻系統崩潰。下面以常見的Redis緩存元件為例來講解這三種場景及解決方案。

大前提

當我們使用緩存時,目标通常有兩個:第一,提升響應效率和并發量;第二,減輕資料庫的壓力。

而本文中所提到的這三種場景:緩存穿透、緩存雪崩和緩存擊穿的發生,都是因為在某些特殊情況下,緩存失去了預期的功能所緻。

當緩存失效或沒有抵擋住流量,流量直接湧入到資料庫,在高并發的情況下,可能直接擊垮資料庫,導緻整個系統崩潰。

這就是我們需要知道的大前提,而緩存穿透、緩存雪崩和緩存擊穿,隻不過是在這個大前提下的不同場景的細分場景而已。

緩存穿透

大多數情況,緩存可以減少資料庫的查詢,提升系統性能。

通常流程是:一個請求過來,先查詢是否在緩存當中,如果緩存中存在,則直接傳回。如果緩存中不存在對應的資料,則檢索資料庫,如果資料庫中存在對應的資料,則更新緩存并傳回結果。如果資料庫中也不存在對應的資料,則傳回空或錯誤。

緩存穿透(cache penetration)是使用者通路的資料既不在緩存當中,也不在資料庫中。出于容錯的考慮,如果從底層資料庫查詢不到資料,則不寫入緩存。這就導緻每次請求都會到底層資料庫進行查詢,緩存也失去了意義。當高并發或有人利用不存在的Key頻繁攻擊時,資料庫的壓力驟增,甚至崩潰,這就是緩存穿透問題。

緩存擊穿、緩存穿透、緩存雪崩介紹及解決思路

緩存穿透

緩存穿透發生的場景一般有兩類:

  • 原來資料是存在的,但由于某些原因(誤删除、主動清理等)在緩存和資料庫層面被删除了,但前端或前置的應用程式依舊保有這些資料;
  • 惡意攻擊行為,利用不存在的Key或者惡意嘗試導緻産生大量不存在的業務資料請求。

緩存穿透通常有四種解決方案,我們逐一介紹分析。

方案一:緩存空值(null)或預設值

分析業務請求,如果是正常業務請求時發生緩存穿透現象,可針對相應的業務資料,在資料庫查詢不存在時,将其緩存為空值(null)或預設值。需要注意的是,針對空值的緩存失效時間不宜過長,一般設定為5分鐘之内。當資料庫被寫入或更新該key的新資料時,緩存必須同時被重新整理,避免資料不一緻。

方案二:業務邏輯前置校驗

在業務請求的入口處進行資料合法性校驗,檢查請求參數是否合理、是否包含非法值、是否惡意請求等,提前有效阻斷非法請求。比如,根據年齡查詢時,請求的年齡為-10歲,這顯然是不合法的請求參數,直接在參數校驗時進行判斷傳回。

方案三:使用布隆過濾器請求白名單

在寫入資料時,使用布隆過濾器進行标記(相當于設定白名單),業務請求發現緩存中無對應資料時,可先通過查詢布隆過濾器判斷資料是否在白名單内,如果不在白名單内,則直接傳回空或失敗。

方案四:使用者黑名單限制

當發生異常情況時,實時監控通路的對象和資料,分析使用者行為,針對故意請求、爬蟲或攻擊者,進行特定使用者的限制;

當然,可能針對緩存穿透的情況,也有可能是其他的原因引起,可以針對具體情況,采用對應的措施。

緩存雪崩

在使用緩存時,通常會對緩存設定過期時間,一方面目的是保持緩存與資料庫資料的一緻性,另一方面是減少冷緩存占用過多的記憶體空間。

但當緩存中大量熱點緩存采用了相同的實效時間,就會導緻緩存在某一個時刻同時實效,請求全部轉發到資料庫,進而導緻資料庫壓力驟增,甚至當機。進而形成一系列的連鎖反應,造成系統崩潰等情況,這就是緩存雪崩(Cache Avalanche)。

緩存擊穿、緩存穿透、緩存雪崩介紹及解決思路

緩存雪崩

上面講到的是熱點key同時失效的場景,另外就是由于某些原因導緻緩存服務當機、挂掉或不響應,也同樣會導緻流量直接轉移到資料庫。

是以,緩存雪崩的場景通常有兩個:

  • 大量熱點key同時過期;
  • 緩存服務故障;

緩存雪崩的解決方案:

  • 通常的解決方案是将key的過期時間後面加上一個

    随機數

    (比如随機1-5分鐘),讓key均勻的失效。
  • 考慮用隊列或者鎖的方式,保證緩存單線程寫,但這種方案可能會影響并發量。
  • 熱點資料可以考慮不失效,背景異步更新緩存,适用于不嚴格要求緩存一緻性的場景。
  • 雙key政策,主key設定過期時間,備key不設定過期時間,當主key失效時,直接傳回備key值。
  • 建構緩存高可用叢集(針對緩存服務故障情況)。
  • 當緩存雪崩發生時,服務熔斷、限流、降級等措施保障。

緩存擊穿

緩存雪崩是指隻大量熱點key同時失效的情況,如果是單個熱點key,在不停的扛着大并發,在這個key失效的瞬間,持續的大并發請求就會擊破緩存,直接請求到資料庫,好像蠻力擊穿一樣。這種情況就是緩存擊穿(Cache Breakdown)。

緩存擊穿、緩存穿透、緩存雪崩介紹及解決思路

緩存擊穿

從定義上可以看出,緩存擊穿和緩存雪崩很類似,隻不過是緩存擊穿是一個熱點key失效,而緩存雪崩是大量熱點key失效。是以,可以将緩存擊穿看作是緩存雪崩的一個子集。

緩存擊穿的解決方案:

  • 使用互斥鎖(Mutex Key),隻讓一個線程建構緩存,其他線程等待建構緩存執行完畢,重新從緩存中擷取資料。單機通過synchronized或lock來處理,分布式環境采用分布式鎖。
  • 熱點資料不設定過期時間,背景異步更新緩存,适用于不嚴格要求緩存一緻性的場景。
  • ”提前“使用互斥鎖(Mutex Key):在value内部設定一個比緩存(Redis)過期時間短的過期時間辨別,當異步線程發現該值快過期時,馬上延長内置的這個時間,并重新從資料庫加載資料,設定到緩存中去。

小結

本文介紹了在使用緩存時經常會遇到的三種異常情況:緩存穿透、緩存雪崩和緩存擊穿。

三種異常情況從根本上來說都是因為本應該通路緩存的,但是緩存不存在或服務異常,導緻流量直接進入了資料庫層面。

其中緩存雪崩和緩存擊穿是因為資料不存在(或服務異常擷取不到),導緻大量請求通路資料庫,進而導緻資料庫壓力驟增,甚至崩潰。

而緩存穿透則是由于資料本身就不存在,導緻緩存沒有進行資料緩存,流量進入資料庫層。

針對不同的緩存異常場景,可選擇不同的方案來進行處理。當然,除了上述方案,我們還可以限流、降級、熔斷等服務層的措施,也可以考慮資料庫層是否可以進行橫向擴充,當緩存異常發生時,確定資料庫能夠抗住流量,不至于讓整個系統崩潰。

背景

在現代軟體架構中,緩存的應用已經非常普及。緩存的使用在面試和實踐中都是避不開的硬技能、硬知識,如果你說還不太熟悉緩存的使用,可能都不好意思說自己是程式員。

這篇文章,帶大家進一步學習在緩存使用中不得不考慮三個特殊場景:緩存穿透、緩存雪崩、緩存擊穿。

為什麼說不得不考慮?因為如果不考慮這些特殊的場景,在高并發的情況可能直接導緻系統崩潰。下面以常見的Redis緩存元件為例來講解這三種場景及解決方案。

大前提

當我們使用緩存時,目标通常有兩個:第一,提升響應效率和并發量;第二,減輕資料庫的壓力。

而本文中所提到的這三種場景:緩存穿透、緩存雪崩和緩存擊穿的發生,都是因為在某些特殊情況下,緩存失去了預期的功能所緻。

當緩存失效或沒有抵擋住流量,流量直接湧入到資料庫,在高并發的情況下,可能直接擊垮資料庫,導緻整個系統崩潰。

這就是我們需要知道的大前提,而緩存穿透、緩存雪崩和緩存擊穿,隻不過是在這個大前提下的不同場景的細分場景而已。

緩存穿透

大多數情況,緩存可以減少資料庫的查詢,提升系統性能。

通常流程是:一個請求過來,先查詢是否在緩存當中,如果緩存中存在,則直接傳回。如果緩存中不存在對應的資料,則檢索資料庫,如果資料庫中存在對應的資料,則更新緩存并傳回結果。如果資料庫中也不存在對應的資料,則傳回空或錯誤。

緩存穿透(cache penetration)是使用者通路的資料既不在緩存當中,也不在資料庫中。出于容錯的考慮,如果從底層資料庫查詢不到資料,則不寫入緩存。這就導緻每次請求都會到底層資料庫進行查詢,緩存也失去了意義。當高并發或有人利用不存在的Key頻繁攻擊時,資料庫的壓力驟增,甚至崩潰,這就是緩存穿透問題。

緩存擊穿、緩存穿透、緩存雪崩介紹及解決思路

緩存穿透

緩存穿透發生的場景一般有兩類:

  • 原來資料是存在的,但由于某些原因(誤删除、主動清理等)在緩存和資料庫層面被删除了,但前端或前置的應用程式依舊保有這些資料;
  • 惡意攻擊行為,利用不存在的Key或者惡意嘗試導緻産生大量不存在的業務資料請求。

緩存穿透通常有四種解決方案,我們逐一介紹分析。

方案一:緩存空值(null)或預設值

分析業務請求,如果是正常業務請求時發生緩存穿透現象,可針對相應的業務資料,在資料庫查詢不存在時,将其緩存為空值(null)或預設值。需要注意的是,針對空值的緩存失效時間不宜過長,一般設定為5分鐘之内。當資料庫被寫入或更新該key的新資料時,緩存必須同時被重新整理,避免資料不一緻。

方案二:業務邏輯前置校驗

在業務請求的入口處進行資料合法性校驗,檢查請求參數是否合理、是否包含非法值、是否惡意請求等,提前有效阻斷非法請求。比如,根據年齡查詢時,請求的年齡為-10歲,這顯然是不合法的請求參數,直接在參數校驗時進行判斷傳回。

方案三:使用布隆過濾器請求白名單

在寫入資料時,使用布隆過濾器進行标記(相當于設定白名單),業務請求發現緩存中無對應資料時,可先通過查詢布隆過濾器判斷資料是否在白名單内,如果不在白名單内,則直接傳回空或失敗。

方案四:使用者黑名單限制

當發生異常情況時,實時監控通路的對象和資料,分析使用者行為,針對故意請求、爬蟲或攻擊者,進行特定使用者的限制;

當然,可能針對緩存穿透的情況,也有可能是其他的原因引起,可以針對具體情況,采用對應的措施。

緩存雪崩

在使用緩存時,通常會對緩存設定過期時間,一方面目的是保持緩存與資料庫資料的一緻性,另一方面是減少冷緩存占用過多的記憶體空間。

但當緩存中大量熱點緩存采用了相同的實效時間,就會導緻緩存在某一個時刻同時實效,請求全部轉發到資料庫,進而導緻資料庫壓力驟增,甚至當機。進而形成一系列的連鎖反應,造成系統崩潰等情況,這就是緩存雪崩(Cache Avalanche)。

緩存擊穿、緩存穿透、緩存雪崩介紹及解決思路

緩存雪崩

上面講到的是熱點key同時失效的場景,另外就是由于某些原因導緻緩存服務當機、挂掉或不響應,也同樣會導緻流量直接轉移到資料庫。

是以,緩存雪崩的場景通常有兩個:

  • 大量熱點key同時過期;
  • 緩存服務故障;

緩存雪崩的解決方案:

  • 通常的解決方案是将key的過期時間後面加上一個

    随機數

    (比如随機1-5分鐘),讓key均勻的失效。
  • 考慮用隊列或者鎖的方式,保證緩存單線程寫,但這種方案可能會影響并發量。
  • 熱點資料可以考慮不失效,背景異步更新緩存,适用于不嚴格要求緩存一緻性的場景。
  • 雙key政策,主key設定過期時間,備key不設定過期時間,當主key失效時,直接傳回備key值。
  • 建構緩存高可用叢集(針對緩存服務故障情況)。
  • 當緩存雪崩發生時,服務熔斷、限流、降級等措施保障。

緩存擊穿

緩存雪崩是指隻大量熱點key同時失效的情況,如果是單個熱點key,在不停的扛着大并發,在這個key失效的瞬間,持續的大并發請求就會擊破緩存,直接請求到資料庫,好像蠻力擊穿一樣。這種情況就是緩存擊穿(Cache Breakdown)。

緩存擊穿、緩存穿透、緩存雪崩介紹及解決思路

緩存擊穿

從定義上可以看出,緩存擊穿和緩存雪崩很類似,隻不過是緩存擊穿是一個熱點key失效,而緩存雪崩是大量熱點key失效。是以,可以将緩存擊穿看作是緩存雪崩的一個子集。

緩存擊穿的解決方案:

  • 使用互斥鎖(Mutex Key),隻讓一個線程建構緩存,其他線程等待建構緩存執行完畢,重新從緩存中擷取資料。單機通過synchronized或lock來處理,分布式環境采用分布式鎖。
  • 熱點資料不設定過期時間,背景異步更新緩存,适用于不嚴格要求緩存一緻性的場景。
  • ”提前“使用互斥鎖(Mutex Key):在value内部設定一個比緩存(Redis)過期時間短的過期時間辨別,當異步線程發現該值快過期時,馬上延長内置的這個時間,并重新從資料庫加載資料,設定到緩存中去。

小結

本文介紹了在使用緩存時經常會遇到的三種異常情況:緩存穿透、緩存雪崩和緩存擊穿。

三種異常情況從根本上來說都是因為本應該通路緩存的,但是緩存不存在或服務異常,導緻流量直接進入了資料庫層面。

其中緩存雪崩和緩存擊穿是因為資料不存在(或服務異常擷取不到),導緻大量請求通路資料庫,進而導緻資料庫壓力驟增,甚至崩潰。

而緩存穿透則是由于資料本身就不存在,導緻緩存沒有進行資料緩存,流量進入資料庫層。

針對不同的緩存異常場景,可選擇不同的方案來進行處理。當然,除了上述方案,我們還可以限流、降級、熔斷等服務層的措施,也可以考慮資料庫層是否可以進行橫向擴充,當緩存異常發生時,確定資料庫能夠抗住流量,不至于讓整個系統崩潰。