作者:劉須華
一、背景概述:
R2M快取的使用,極大的提升了應用程式的效能和效率,特別是資料查詢方面。而快取最常見的問題是快取穿透、擊穿和雪崩,在高併發下這三種情況都會有大量請求落到資料庫,導致資料庫資源佔滿,引起資料庫故障。平時對快取測試時除了關注增刪修改查詢等基本功能,應該要重點關注快取穿透、擊穿和雪崩三種異常場景的測試覆蓋,避免出現線上事故。
二、基本概念說明:
1、快取擊穿:是指在超級熱點資料突然過期,導致針對超級熱點的資料請求在過期期間直接打到資料庫,這樣資料庫伺服器會因為某一超熱資料導致壓力過大而崩掉。
2、快取穿透:是指查詢的資料在快取和資料庫中都不存在,導致每一次請求資料從快取中都獲取不到,而將請求打到資料庫伺服器,但資料庫中也沒有對應的資料,最後每一次請求都到資料庫;如果在高併發場景或有人惡意攻擊,就會導致後臺資料庫伺服器壓力增大,最終系統可能崩掉。
3、快取雪崩:是指突然快取層不可用,導致大量請求直接打到資料庫,最終由於資料庫壓力過大可能導致系統崩掉。快取層不可用指以下兩方面:快取伺服器當機,系統將請求打到資料庫; 快取資料突然大範圍集中過期失效,導致大量請求打到資料庫重新載入資料, 與快取擊穿的區別在於這裡針對很多key快取,前者則是某一個key。
三、測試工具(非必須):
1、使用Titan壓測平臺進行併發請求測試
2、使用jmeter工具模擬併發請求
四、測試方法舉例說明(非必須):
環境:測試環境
工具:jmeter
(1)快取穿透場景
測試方法:查詢一個根本不存在的資料,快取層和儲存層都不會命中。
查詢介面相關程式碼實現:
透過JMETER模擬多次重複呼叫:單執行緒重複呼叫
檢視日誌結果: 從日誌可以看出:執行併發請求後, 所有請求每次都走向了資料庫。
預防方案:
當資料庫查詢為空時,將快取賦值預設值,後續查詢都走快取,減少資料庫壓力。
上述介面,增加賦值為empty,則第一次查詢到資料庫為空,後續查詢都查詢到快取中,快取值為empty。
再次執行併發測試:從日誌可以看出,可以看出每個ID都只執行了一次資料庫查詢並設定快取,之後請求都命中了快取,有效防止了快取穿透問題。
(2)快取擊穿場景
測試方法:對某個Key有大量的併發請求,這時從快取中刪除這個key。模擬熱key過期失效的場景。這個時候大併發的請求可能會瞬間把後端DB壓垮。
介面相關部分程式碼實現:
操作步驟:
1、查詢pin為liuxuhua的請求,這時pin為liuxuhua的資料會載入到快取
2、再次查詢pin為liuxuhua的請求,命中快取
3、50併發請求pin為liuxuhua的資料,這個時候請求全部命中快取
4、將pin為liuxuhua的快取手動刪除,模擬快取失效
5、50併發請求pin為liuxuhua的資料,這個時候大量請求走向資料庫,pin為liuxuhua
的快取被擊穿
檢視日誌結果:
預防方案:
在設定預設快取值的基礎上,進行加鎖處理。只有拿到鎖的第一個執行緒去請求資料庫,然後插入快取,當然每次拿到鎖的時候都要去查詢一下快取有沒有。
從日誌記錄可以看到只有一個請求執行了資料庫查詢並設定快取,其他請求都命中了快取, 有效防止了快取的擊穿。
(3)快取雪崩
測試方法:對多個使用到快取的介面進行併發呼叫,設定這些快取時間已過期(即刪除快取),呼叫時這些介面查詢快取時無資料,去查詢資料庫,這些請求都指向資料庫,資料庫壓力增大,耗時增加。
模擬介面:
透過JMETER模擬多次重複呼叫:單執行緒多介面重複呼叫
檢視日誌結果:可以看出大量請求到達資料庫,並且同一個pin或id執行了多次資料庫查詢
預防方案:
增加限流操作,即介面頻繁呼叫時,增加一個快取,設定時間為3s,3s內處理一定次數的請求,超過限制次數的請求直接返回結果,不做處理。
介面:3s內處理6次請求,超過則不處理;
從日誌可以看出:可以看到每個都只查詢了一次資料庫並設定快取,之後的請求都命中了快取
五、測試指標:(或者叫透過標準,包括關注點以及意義)
1、模擬快取穿透場景測試,每個不存在的資料都只執行了一次資料庫查詢並設定快取,之後請求都命中了快取,有效防止了快取穿透問題。
2、模擬快取雪崩場景測試,每個快取失效的資料都只執行了一次資料庫查詢並設定快取,之後請求都命中了快取。
3、模擬快取擊穿場景測試,快取失效的那個資料只有一個請求執行了資料庫查詢並設定快取,其他請求都命中了快取。
六、適用業務場景:
1、秒殺活動
2、熱門營銷活動
3、618和雙11大促
七、研發側常見解決方案(參考):
1、快取穿透解決方案:
1、快取空值
之所以發生穿透,是因為快取中沒有儲存這些資料的key,從而每次都查詢資料庫
我們可以為這些key在快取中設定對應的值為null,後面查詢這個key的時候就不用查詢資料庫了
當然為了健壯性,我們要對這些key設定過期時間,以防止真的有資料
2、BloomFilter
BloomFilter 類似於一個hbase set 用來判斷某個元素(key)是否存在於某個集合中
我們把有資料的key都放到BloomFilter中,每次查詢的時候都先去BloomFilter判斷,如果沒有就直接返回null
注意BloomFilter沒有刪除操作,對於刪除的key,查詢就會經過BloomFilter然後查詢快取再查詢資料庫,所以BloomFilter可以結合快取空值用,對於刪除的key,可以在快取中快取null 快取擊穿
2、快取擊穿解決方案:
採用分散式鎖,只有拿到鎖的第一個執行緒去請求資料庫,然後插入快取,當然每次拿到鎖的時候都要去查詢一下快取有沒有
3、快取雪崩解決方案:
1、採用叢集,降低服務當機的機率
2、ehcache本地快取 + 限流&降級
3、均勻過期,通常可以為有效期增加隨機值