-
1 # 網路圈
-
2 # 狂客說技術
凌晨四點醒來看到這個問題,很有感觸,索性覺也不睡了和大家好好聊聊這個話題,因為自己工作中遇到過快取雪崩問題。快取的概念以及使用我就不多說了,直接來聊乾貨!關注必回!
快取穿透和擊穿,簡單來說就是一個快取資料被請求時沒有直接從快取中獲取到值,轉而繞過快取,直接讀取底層資料,中間層快取的舒壓作用沒有得到體現,訪問高峰期大批次的請求繞過快取直接打到資料庫上的情況。換一種更容易理解的表達方式,大部分快取系統,都是按照key值去快取查詢,如果不存在對應的value,或者快取讀取超時,就會去DB中查詢 。如果請求的併發量很大,就會對後端的DB系統造成很大的壓力。這就叫做快取穿透和擊穿。事故快取穿透和擊穿的誘發原因大機率有以下幾種。1.大量快取同時過期,2.單臺快取伺服器短時間內因為網路問題超時3.執行緒池連結被用盡!4.惡意穿透,惡意請求大量訪問快取中不存在的資料!擊穿和穿透場景不盡相同,擊穿熱點key在高峰期失效!穿透大機率指惡意訪問快取中不存在的key,故而解決方式也有差別,手機碼字不易我就糅合在一起說。方案一,互斥鎖排隊處理,key獲取value值為空時,鎖上,從資料庫中load資料後再釋放鎖。若其它執行緒獲取鎖失敗,則等待一段時間後重試。方案二,閘道器中進行介面限流與熔斷、降級。方案三,透過谷歌的布魯過濾器進行快速篩選過濾。
分享讓我們成長!
-
3 # 會點程式碼的大叔
快取穿透
很多專案在使用Redis或其他快取框架的時候,都是先查詢快取,查詢不的話再查詢資料庫,查到之後再放到記憶體中;如果一個key值本身就不存在,那麼每一次都會查詢資料庫,也就是常說的【快取穿透】。
應對方法:
如果在Redis中查詢不到,並且查詢資料庫也沒有結果,那麼就將這個key寫入到Redis中,value=空,並設定一個超時過期時間,例如五分鐘,那麼五分鐘以內的對這個可以的所有查詢就可以攔截下來,如果資料庫有key對應的資料了,那麼五分鐘後Redis中的快取過期,會訪問資料庫並載入快取;但是如果被惡意攻擊,每次請求的key都不相同且不存在,那麼依然會穿透到資料庫;
布隆過濾器:將可能存在的資料Hash到一個足夠大的bitmap上,它可以告訴你 “某個key一定不存在或者可能存在”,一個一定不存在的資料會被bitmap攔截。
快取雪崩很多時候,Redis中的快取是要設定過期時間的,假如Redis中的資料,過期時間都設定成一樣的,那麼到了時間之後,全部快取過期失效,下一秒所有的請求都會訪問資料庫,那麼資料庫可能因為訪問量多大導致“崩潰”,這就是快取雪崩。
應對方法:
最暴力的解決辦法,快取不設定自動過期時間,只要快取不崩,資料庫就不會崩。
另外一個辦法,就是讓快取過期時間不那麼一致,比如一批快取資料24小時後過期,那麼就在這個基礎上,每條快取的過期時間前後隨機1-6000秒(1-10分鐘)。
快取併發大多數時候,我們的程式訪問Redis都不可能是單執行緒,那麼當多個Client併發對Redis進行set key操作的時候,可能會產生一些問題;其實Redis本身是單執行緒的,這種時候會按照先後順序進行操作;或者把操作放在佇列中,按順序執行;
但比如這種情況:
token過期,有兩個執行緒都去重新獲取token;
執行緒1獲取token1;
執行緒2獲取到token2,此時token1過期;
執行緒1把token1放到Redis,再拿著token1去呼叫服務,發現過期了,繼續去請求token3,此時token2過期;
執行緒2把token2放到Redis,再拿著token2去呼叫服務,發現過期了,繼續去請求token4,此時token3過期;
... ...
這就需要我們在更新快取的時候,做一些控制了。
-
4 # 雲計算那些事兒
Redis快取雪崩解決方案
由於快取層承載著大量請求,有效地保護了儲存層,但是如果快取層由於某些原因不能提供服務,於是所有的請求都會達到儲存層,儲存層的呼叫量會暴增,造成儲存層也會級聯宕機的情況。快取雪崩的英文原意是stampeding herd(奔逃的野牛),指的是快取層宕掉後,流量會像奔逃的野牛一樣,打向後端儲存。
預防和解決快取雪崩問題,可以從以下三個方面進行著手。1)保證快取層服務高可用性。和飛機都有多個引擎一樣,如果快取層設計成高可用的,即使個別節點、個別機器、甚至是機房宕掉,依然可以提供服務,例如前面介紹過的Redis Sentinel和Redis Cluster都實現了高可用。2)依賴隔離元件為後端限流並降級。無論是快取層還是儲存層都會有出錯的機率,可以將它們視同為資源。作為併發量較大的系統,假如有一個資源不可用,可能會造成執行緒全部阻塞(hang)在這個資源上,造成整個系統不可用。降級機制在高併發系統中是非常普遍的:比如推薦服務中,如果個性化推薦服務不可用,可以降級補充熱點資料,不至於造成前端頁面是開天窗。在實際專案中,我們需要對重要的資源(例如Redis、MySQL、HBase、外部介面)都進行隔離,讓每種資源都單獨執行在自己的執行緒池 中,即使個別資源出現了問題,對其他服務沒有影響。但是執行緒池如何管理,比如如何關閉資源池、開啟資源池、資源池閥值管理,這些做起來還是相當複雜的。這裡推薦一個Java依賴隔離工具Hystrix(https://github.com/netflix/hystrix),如圖11-15所示。Hystrix是解決依賴隔離的利器,但是該內容已經超出本書的範圍,同時只適用於Java應用, 所以這裡不會詳細介紹。3)提前演練。在專案上線前,演練快取層宕掉後,應用以及後端的負載情況以及可能出現的問題,在此基礎上做一些預案設定。
回覆列表
Redis因其簡單、高效的特點被廣泛應用,如今中小型網站都在使用Redis了。我們在使用Redis時,在高併發場景下,Redis容易出現快取併發、快取穿透及雪崩的現象。
快取併發、快取雪崩、快取穿透這三者還是有區別的,我們先來了解一下。
1、快取併發
我們說的快取併發指的是多個Redis客戶端同時SET Key時會引起併發問題。我們知道,Redis是單執行緒的,在多個Client併發操作時,秉承“先發起先執行”的原則,其它的處於阻塞狀態。
常見快取併發有兩種場景:
快取過期後會從後端資料庫查詢資料然後存入Redis快取,但在高併發情況下可能在還沒來得及將庫中查出來的資料存入Redis時,其它Client又從資料庫裡查詢資料再存入Redis了。這樣一來會造成多個請求併發的從資料庫獲取資料,對後端資料庫會造成壓力。
在高併發場景下,某個Key正在更新時,可能有很多Client在獲取此Key的資料,這樣會導致“髒資料”。
如何解決快取併發問題呢?我們常藉助“鎖”來實現,具體實現邏輯為:
在更新快取或者讀取過期快取的情況下,我們先獲取“鎖”,當完成了快取資料的更新後再釋放鎖,這樣一來,其它的請求需要在釋放鎖之後執行,會犧牲一點時間。
2、快取穿透
什麼是快取穿透現象呢?我們先來說下快取正常的邏輯。
正常情況下我們都是根據快取Key檢視是否存在值或已過期,如果不存在我們則向後端資料庫查詢並將查詢結果存入快取中(資料庫有結果時存入Redis,沒結果時就沒有存入Redis),下次請求時只要快取沒過期就直接從快取中獲取資料。
但是,如果我們在上一步過程中,從資料庫查詢出的結果是空的,所以沒有存入Redis,然後又跑到後端資料庫進行查詢,即每一次請求都會落到資料庫去查詢,這樣就導致了快取命中率低的現象,這就是快取穿透。
所以說快取穿透可以理解為訪問了一個不存在的Key,快取無效,沒有發揮作用,每次查詢流量最終落在了資料庫上面。
還有一種情況,即使是一個存在的Key,在它快取過期的那一瞬間,如果網站併發大,那在此Key沒有重新生效時,所有的請求全部擊穿到資料庫上了。
如果避免快取穿透呢?最簡單的方式就是即使資料庫查詢結果是空的,我們給一個預設值或者直接將空值存入Redis。
3、快取雪崩
什麼是快取雪崩呢?快取雪崩指的是在一段時間段內,Redis絕大部分Key集體失效的現象。
造成這種現象的原因很簡單:大量的Key設定的過期時間是相同的,或者都在同一段時間段內。當快取在同一段時間段內集體失效後,你會發現資料庫壓力一下子就上去了(DB洪峰),最終引起雪崩現象。
如何避免呢?給兩個方案參考:
給所有快取時間設定一個固定的TTL+隨機時間TTL,這樣能保證所有Key不會同一時間內集體過期;
快取副本機制,給每個Key設定一個副本,副本的TTL時間較長。
綜上,在快取併發情況嚴重時,熱點Key在失效的瞬間會引起快取擊穿(小雪崩),如果所有的Key在同一時間內都失效了則會引起快取雪崩現象,導致後端資料庫壓力聚增。