一篇吃透Redis緩存穿透、雪崩、擊穿問題
前言:在學Redis之前我們查詢數(shù)據(jù)的時候都是直接查詢數(shù)據(jù)庫的,但是這樣會有一個潛在的問題:“如果用戶量很大,所有請求都去訪問數(shù)據(jù)庫,那么會使數(shù)據(jù)庫壓力過大,導致性能下降甚至宕機”。因此,我們需要把經(jīng)常訪問的數(shù)據(jù)放到緩存中,這里我們用Redis作為緩存。
但是,使用Redis作為緩存的過程中我們一般如下,如下圖:我們查詢某個數(shù)據(jù),前端發(fā)送請求到后端,后端根據(jù)請求去查詢數(shù)據(jù),一開始先去Redis中查有無這個數(shù)據(jù),如果有則直接返回,沒有則去數(shù)據(jù)庫中查找并且將查找到的結果返回,如果數(shù)據(jù)庫中沒有則返回錯誤信息。

那么,在使用Redis作為緩存的過程中我們避免不了會遇到以下幾個常見的問題:①Redis與數(shù)據(jù)庫的數(shù)據(jù)一致性問題。②緩存穿透。③緩存雪崩。④緩存擊穿。
我們先來說①緩存與數(shù)據(jù)庫的數(shù)據(jù)庫一致性問題。
對于Redis作為緩存我們有以下用法:①只讀緩存。②讀寫緩存。
只讀緩存是指對于修改數(shù)據(jù)的時候,我們只對數(shù)據(jù)庫進行修改,同時刪除緩存,這樣我們永遠能保證數(shù)據(jù)庫中有最新的數(shù)據(jù),但是這樣每次修改數(shù)據(jù)的時候,我們查找該數(shù)據(jù)的時候都需要查找一次數(shù)據(jù)庫,因此性能會有所降低。
讀寫緩存是指我們修改數(shù)據(jù)的時候對緩存的數(shù)據(jù)也直接進行修改,那么又可以分為兩種:①同步讀寫②異步讀寫。
同步讀寫是指修改數(shù)據(jù)的時候同時修改緩存和數(shù)據(jù)庫,并且通過事務的特性保證二者數(shù)據(jù)一致性,但是由于緩存的速度遠快于數(shù)據(jù)庫的速度,因此性能還是會有一定的限制。
異步讀寫是指我們每次修改數(shù)據(jù)都是在緩存中修改,每隔一段時間將緩存中的數(shù)據(jù)導入數(shù)據(jù)庫中,這樣每次修改的時間只是修改緩存數(shù)據(jù)的時間,性能大大提高。但是這樣會存在一個隱患:“當Redis突發(fā)情況宕機的時候,數(shù)據(jù)還沒來得及導入數(shù)據(jù)庫,那么這段時間還沒保存進數(shù)據(jù)庫的數(shù)據(jù)就會丟失”,因此一致性無法保證。
然后我們來說說②緩存穿透。由我們Redis作為緩存的流程圖可以知道:我們每次查詢數(shù)據(jù)的時候都是先查詢緩存,查詢不到再查數(shù)據(jù)庫,如果數(shù)據(jù)庫中也查詢不到則返回錯誤信息。

那么,對于一個查詢不到的數(shù)據(jù),如果有心懷不軌的人,寫一個程序,多線程并發(fā)的無限查詢這個數(shù)據(jù),那么我們每次都需要訪問數(shù)據(jù)庫,會導致數(shù)據(jù)庫性能下降甚至宕機,這就是緩存穿透。
那么,我們?nèi)绾蝸斫鉀Q緩存穿透呢?這里我們說兩種方法:
方法一:Redis緩存中存儲空值。我們可以知道,緩存穿透是由于某些不存在的數(shù)據(jù),每次查詢,我們在緩存中都查找不到該數(shù)據(jù),因此每次都需要去訪問數(shù)據(jù)庫。那么我們可以不可以對于這些數(shù)據(jù)也存入緩存中呢?這樣我們每次查找這些數(shù)據(jù),就只會第一次查找數(shù)據(jù)庫,后面都是查找緩存了。那么有人會問了?“咦,不存在的數(shù)據(jù)怎么查找呢?”所以我們這邊是將某個不存在的數(shù)據(jù)存儲在緩存中,并且存儲的值為空字符串(也可以是其他的,這里取決于你與前端兄弟的約定)。如下圖:

因此,這樣我們對于這些惡意數(shù)據(jù),就只能“騷擾”我們的寶貝數(shù)據(jù)庫一次了,便解決了緩存穿透的問題,那么還有一個疑問就是:如果將來這些數(shù)據(jù)有了,但是每次查詢的時候緩存都直接返回空不是嘛?不會的,因為我們以后對于數(shù)據(jù)庫插入數(shù)據(jù)的同時會對Redis緩存進行一個Set,這個Set數(shù)據(jù)的操作會直接覆蓋原有不存在的數(shù)據(jù),因此并不會出現(xiàn)這種問題。
方法二:布隆過濾器。大致就是在前端頁面和緩存直接多了一個布隆過濾器

布隆過濾器(Bloom Filter)是1970年由布隆提出的。它實際上是一個很長的二進制向量和一系列隨機映射函數(shù)。布隆過濾器可以用于檢索一個元素是否在一個集合中。它的優(yōu)點是空間效率和查詢時間都比一般的算法要好的多,缺點是有一定的誤識別率和刪除困難。布隆過濾器可以告訴我們 “某樣東西一定不存在或者可能存在”,也就是說布隆過濾器說這個數(shù)不存在則一定不存,布隆過濾器說這個數(shù)存在可能不存在。
③緩存雪崩,什么是緩存雪崩呢?緩存雪崩指的是在同一時間大量Redis緩存中存儲的key過期或者Redis服務器直接宕機,并且大量的請求查詢這些數(shù)據(jù)的時候,會導致大量請求一窩蜂的涌向數(shù)據(jù)庫進行查詢,導致數(shù)據(jù)庫壓力過大,性能下降甚至宕機。那么如何解決緩存雪崩呢?
對于情況一:大量key同時過期,這里說幾種解決方法:
①設置緩存key過期時間可以隨機設置,這樣不會使得大量的key同一時間段內(nèi)過期。
②服務降級:指的是對于一些非核心數(shù)據(jù)來說(比如查詢一些無關緊要的數(shù)據(jù)時)我們可以預先設置一些值,當無法訪問緩存的時候,這些數(shù)據(jù)不會直接查詢數(shù)據(jù)庫,而是返回預先設置的值,比如一些錯誤信息。
對于情況二:Redis服務器直接宕機,這里說幾種解決方法:
①搭建Redis服務集群:嘗試構建 Redis 的高可用集群,比如當某主節(jié)點掛掉了,集群能夠馬上重新選出新的主節(jié)點。
②業(yè)務中實現(xiàn)服務熔斷或者請求限流機制:
服務熔斷:如果監(jiān)聽到發(fā)生了緩存雪崩,直接暫停對緩存服務的請求,但是這種對業(yè)務的影響比較大;
服務限流:可以在入口做限流,不要讓所有的請求都流入到后端的服務中;
④緩存擊穿:緩存雪崩指的是大量數(shù)據(jù)無法從Redis查詢到,而同時去查詢數(shù)據(jù)庫導致,緩存擊穿則是某些熱點key,比如雙十一搶蘋果手機,如果突然間Redis緩存對于這個數(shù)據(jù)過期了,那么這一瞬間大量搶蘋果手機的請求都會去訪問數(shù)據(jù)庫,導致數(shù)據(jù)庫性能下降甚至宕機這里我們講兩種解決方法:①Redis互斥鎖。②緩存數(shù)據(jù)邏輯過期。
方法一:Redis互斥鎖。以上我們知道:對于某個熱點key失效的時候,由于大量查詢該數(shù)據(jù)的請求在緩存中查找不到,因此同時查找數(shù)據(jù)庫導致。那么我們只需要對于每個數(shù)據(jù)設置一個互斥鎖,當在訪問不到緩存的時候,只有一個線程能夠去訪問數(shù)據(jù)庫,其他線程等待,
- 這樣就解決了以上的問題。

但是這樣會導致一個問題:那就是由于其他線程都要等待,會導致性能下降,要等那個拿到互斥鎖的線程查詢完數(shù)據(jù)庫,并且返回數(shù)據(jù)到緩存中才能查到數(shù)據(jù)。
方法二:緩存的數(shù)據(jù)邏輯過期。我們知道,緩存擊穿是由于熱點key過期導致去查詢數(shù)據(jù)庫,那么我們可以這樣想:如果這些熱點key只是邏輯過期(邏輯過期指雖然過期了,但是還是在緩存里面不會刪除,但是程序會知道是已過期的數(shù)據(jù),會訪問一次數(shù)據(jù)庫進行更新),那么不就解決了嗎?因此邏輯過期的解決思路是:對于這些熱點key,先查詢緩存,如果沒過期則直接返回,如果過期了則開一個新的線程
去查詢數(shù)據(jù)庫,而查詢數(shù)據(jù)庫過程中訪問緩存的請求直接返回舊數(shù)據(jù)即可。

但是邏輯過期由于要多一個線程,因此有一定的內(nèi)存消耗,并且更新過程中訪問的請求都是收到舊的數(shù)據(jù),因此一致性有一定的下降。
以上是使用Redis緩存過程中的一些常見問題,后續(xù)會慢慢補充。
以上就是一篇吃透Redis緩存穿透、雪崩、擊穿問題的詳細內(nèi)容,更多關于Redis緩存穿透、雪崩、擊穿的資料請關注腳本之家其它相關文章!
相關文章
阿里云服務器安裝配置redis的方法并且加入到開機啟動(推薦)
這篇文章主要介紹了阿里云服務器安裝配置redis并且加入到開機啟動,需要的朋友可以參考下2017-12-12
Springboot整合Redis與數(shù)據(jù)持久化
這篇文章主要介紹了Springboot整合Redis與Redis數(shù)據(jù)持久化的操作,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-07-07
ubuntu 16.04安裝redis的兩種方式教程詳解(apt和編譯方式)
這篇文章主要介紹了ubuntu 16.04安裝redis的兩種方式教程詳解(apt和編譯方式),需要的朋友可以參考下2018-03-03
RedisDesktopManager?連接redis的方法
這篇文章主要介紹了RedisDesktopManager?連接redis,需要的朋友可以參考下2023-08-08

