快取穿透和雪崩可以看做乙個問題,只是嚴重程度不同;當乙個請求到達redis之後發現沒有對應的快取資料,然後向db傳送資料請求,如果能獲取到資料那問題就停留在了快取穿透上,db獲取到的資料會快取到redis上;如果db中也沒有對應的資料,並且當這樣的請求達到一定數量級並且耗用完所有的db資源,最終導致db連線異常就出現了快取雪崩問題。
解決快取穿透問題的思路有下述幾種,不管是否從db中查詢到對應的值(沒有值就為null),都在redis中記錄一條快取記錄;在dao層維護一張bitmap,用bit記錄對應的key是否有對應值,從而避免冗餘的db操作;後台執行緒專門用於更新即將過期的redis資料,從而避免快取穿透。
解決快取雪崩問題的思路有下述幾種,在db connection上新增互斥鎖,這樣當大量快取請求失效的時候需要排隊去db請求資料;對設定了相同過期時間的資料設定乙個隨機值,避免資料集體失效;使用雙快取或者多層快取策略,需要配合快取預熱。
如果快取集中在一段時間內失效,發生大量的快取穿透,所有的查詢都落在資料庫上,造成了快取雪崩
由於原有快取失效,新快取未到期間所有原本應該訪問快取的請求都去查詢資料庫了,而對資料庫cpu和記憶體造成巨大壓力,嚴重的會造成資料庫宕機
1)加鎖排隊
mutex互斥鎖解決,redis的setnx去set乙個mutex key,當操作返回成功時,再進行載入資料庫的操作並回設快取,否則,就重試整個get快取的方法
2)資料預熱
快取預熱就是系統上線後,將相關的快取資料直接載入到快取系統。這樣就可以避免在使用者請求的時候,先查詢資料庫,然後再將資料快取的問題。使用者直接查詢事先被預熱的快取資料。可以通過快取reload機制,預先去更新快取,在即將發生大併發訪問前手動觸發載入快取不同的key
3)雙層快取策略
c1為原始快取,c2為拷貝快取,c1失效時,可以訪問c2,c1快取失效時間設定為短期,c2設定為長期
4)定時更新快取策略
實效性要求不高的快取,容器啟動初始化載入,採用定時任務更新或移除快取
5)設定不同的過期時間,讓快取失效的時間點盡量均勻
在平常高併發的系統中,大量的請求同時查詢乙個key時,此時這個key正好失效了,就會導致大量的請求都打到資料庫上面去。這種現象我們稱為快取擊穿
會造成某一時刻資料庫請求量過大,壓力劇增
上面的現象是多個執行緒同時去查詢資料庫的這條資料,那麼我們可以在第乙個查詢資料的請求上使用乙個互斥鎖來鎖住它
其他的執行緒走到這一步拿不到鎖就等著,等第乙個執行緒查詢到了資料,然後做快取。後面的執行緒進來發現已經有快取了,就直接走快取
快取穿透是指使用者查詢資料,在資料庫沒有,自然在快取中也不會有。這樣就導致使用者查詢的時候,在快取中找不到對應key的value,每次都要去資料庫再查詢一遍,然後返回空(相當於進行了兩次無用的查詢)。這樣請求就繞過快取直接查資料庫
2)、有什麼解決方案來防止快取穿透?
如果乙個查詢返回的資料為空(不管是資料不存在,還是系統故障)我們仍然把這個空結果進行快取,但它的過期時間會很短,最長不超過5分鐘。通過這個設定的預設值存放到快取,這樣第二次到快取中獲取就有值了,而不會繼續訪問資料庫
優勢:占用記憶體空間很小,位儲存;效能特別高,使用key的hash判斷key存不存在
將所有可能存在的資料雜湊到乙個足夠大的bitmap中,乙個一定不存在的資料會被這個bitmap攔截掉,從而避免了對底層儲存系統的查詢壓力
在快取之前在加一層bloomfilter,在查詢的時候先去bloomfilter去查詢key是否存在,如果不存在就直接返回,存在再去查詢快取,快取中沒有再去查詢資料庫
應用在查詢資料的時候,先從快取cache中讀取資料,如果快取中沒有,則再從資料庫中讀取資料,得到資料庫的資料之後,將這個資料也放到快取cache中
如果應用要更新某個資料,也是先去更新資料庫中的資料,更新完成之後,則通過指令讓快取cache中的資料失效。
主要是因為這樣做的話,就有2個寫操作的事件了,擔心在併發的情況下會導致髒資料,舉個例子:假如同時有2個請求,請求a和請求b,併發的執行。請求a是要去讀資料,請求b是要去更新資料。初始狀態快取中是沒有資料的,當請求a讀到資料之後,準備往回寫的時候,此刻,請求b正好要更新資料,更新完了資料庫之後,又去把快取更新了,那請求a再往快取中寫的就是舊資料了,屬於髒資料
在極端情況下也可能會產生髒資料。例如,同時有2個請求,請求a和請求b,併發的執行。請求a是要去讀資料,請求b是要去寫資料。假如初始狀態快取中沒有這個資料,那請求a發現快取中沒有資料,就會去資料庫中讀資料,讀到了資料準備寫回快取中,就在這個時候,請求b是要去寫資料的,請求b在寫完資料庫的資料之後,又去設定了快取失效。這個時候,請求a由於在資料庫中讀到了之前的舊資料,開始往快取中寫資料了,此時寫進入的就也是舊資料。那麼最終就會導致,快取中的資料與資料庫的資料不一致,造成了髒資料
應用要讀資料和更新資料都直接訪問快取服務
快取服務同步地將資料更新到資料庫
出現髒資料的概率較低,但是就強依賴快取,對快取服務的穩定性有較大要求
應用要讀資料和更新資料都直接訪問快取服務
快取服務非同步地將資料更新到資料庫(通過非同步任務)
速度快,效率會非常高,但是資料的一致性比較差,還可能會有資料的丟失情況,實現邏輯也較為複雜
redis相關問題彙總
本文問題不分先後順序,具體問題請自己詳細定位。1 redis快取穿透 場景 查詢根本不存在的資料,使得請求直達儲存層,導致其負載過大,甚至宕機。解決方案 1 快取空物件 儲存層未查到相應的資料後,仍然將空值存入到快取層。再次訪問該資料時,快取層會直接返回空值。2 布隆過濾器 將所有存在的key提前存...
android 問題彙總系列之八
如何判斷哪個觸點先釋放 關於socket通訊問題connect failed econnrefused connection refused 大家現在還用tabactivity嗎 求高手指點http通訊,具體如下 軟體啟動頁載入,後台載入下次需要顯示的 android4.1 原始碼camera 是如...
android 問題彙總系列之八
如何判斷哪個觸點先釋放 關於socket通訊問題connect failed econnrefused connection refused 大家現在還用tabactivity嗎 求高手指點http通訊,具體如下 軟體啟動頁載入,後台載入下次需要顯示的 android4.1 原始碼camera 是如...