預防快取穿透方案設計
前言
最近公司有一些公司頻繁發生一些重大故障, 加上最近核心域凌晨比較多的一些快取超時(Caused by: net.spy.memcached.internal.CheckedOperationTimeoutException: Timed out waiting for operation),不得不讓人提高警惕。此時間段超時比較多,是因為該時間段是快取預熱高峰期。
排查有3種原因:
- memcached服務端支援的併發連線數已滿,spymemcache客戶端操作超時;
- memcache客戶端新增獲取資料時,主要spymemcache是基於nio非同步獲取的,所以當獲取資料時會把任務新增任務佇列等待執行,同時spymemcache也會做資料獲取的連結超時驗證,如果超過設定的超時時間(預設時間2500ms)就會報異常;
- 一次性get的key過多;
目前該超時在總請求數佔比相對很小,假如某個時間點,有大部分超時,將導致大部分快取穿透,對mysql資料庫造成巨大壓力。下面我們討論一些關於快取穿透的一些預防措施及相關設計。
快取穿透
我們先來了解一下快取穿透的定義
快取穿透是指使用者查詢資料,在資料庫沒有,自然在快取中也不會有。這樣就導致使用者查詢的時候,在快取中找不到,每次都要去資料庫再查詢一遍,然後返回空(相當於進行了兩次無用的查詢)。這樣請求就繞過快取直接查資料庫,這也是經常提的快取命中率問題.
業界有兩種常用預防快取穿透的方法
(1)採用布隆過濾器,將所有可能存在的資料雜湊到一個足夠大的bitmap中,一個一定不存在的資料會被這個bitmap攔截掉,從而避免了對底層儲存系統的查詢壓力。
(2)如果一個查詢返回的資料為空(不管是資料不存在,還是系統故障),我們仍然把這個空結果進行快取,但它的過期時間會很短,這個根據業務上允許的時間為準。通過這個直接設定的預設值存放到快取,這樣第二次到快取中獲取就有值了,而不會繼續訪問資料庫,這種辦法最簡單粗暴!
針對第一種方法,大體的預防方案設計如下圖
在訪問所有資源(cache, storage)之前,將存在的key用布隆過濾器提前儲存起來,做第一層攔截,例如: 我們的價格服務有1億個sku, 我們可以對所有sku對應的key做一份布隆過濾器,這樣可以過濾掉一些不在本系統定價的一些請求,減少cache\storage資源的壓力。
虛擬碼如下
if (!bloomfilter.mightContain(key)) {
return null;
}
String value = redis.get(key);
if (value == null) {
return null;
} else {
//這裡用mutex鎖實現單執行緒回源i)
value = getFromCacheDb(key);
}
return value;
private String getFromCacheDb(String key) {
String redis = null;
String value = redis.get(key);
if (value == null) {
value = db.get(key);
redis.set(key, value, expire_secs);
redis.del(key_mutex);
} else{
sleep(50);
getFromCacheDb(key);//重試
}
return value;
}
附
一、布隆過濾器是什麼?
- 又快又小的處理方法
- 布隆過濾器(Bloom Filter):是一種空間效率極高的概率型演算法和資料結構,用於判斷一個元素是否在集合中(類似Hashset)。
- 它的核心一個很長的二進位制向量和一系列hash函式
- 陣列長度以及hash函式的個數都是動態確定的
- Hash函式:SHA1,SHA256,MD5…
二、優勢和劣勢
優勢
- 全量儲存但是不儲存元素本身,在某些對保密要求非常嚴格的場合有優勢;
- 空間高效率
- 插入/查詢時間都是常數O(k),遠遠超過一般的演算法
劣勢
- 存在誤算率(False Positive),隨著存入的元素數量增加,誤算率隨之增加;
- 一般情況下不能從布隆過濾器中刪除元素;
- 陣列長度以及hash函式個數確定過程複雜;
參考文章:
https://en.wikipedia.org/wiki/Bloom_filter
http://www.cnblogs.com/haippy/archive/2012/07/13/2590351.html
https://github.com/erikdubbelboer/Redis-Lua-scaling-bloom-filter
https://www.cnblogs.com/atomicbomb/p/8979582.html
相關文章
- 快取穿透防護方案設計快取穿透
- 如何設計快取系統:快取穿透,快取擊穿,快取雪崩解決方案分析快取穿透
- 快取穿透、快取擊穿、快取雪崩、快取預熱快取穿透
- 快取穿透,快取擊穿,快取雪崩解決方案分析快取穿透
- Redis 快取穿透、快取雪崩原理及解決方案Redis快取穿透
- 快取穿透、快取擊穿、快取雪崩概念及解決方案快取穿透
- REDIS快取穿透,快取擊穿,快取雪崩原因+解決方案Redis快取穿透
- 【Redis】快取穿透,快取擊穿,快取雪崩及解決方案Redis快取穿透
- 快取穿透、快取擊穿、快取雪崩區別和解決方案快取穿透
- 快取穿透 快取雪崩快取穿透
- Redis 快取雪崩,快取擊穿和快取穿透技術方案總結Redis快取穿透
- 快取穿透詳解及解決方案快取穿透
- 快取穿透、快取擊穿、快取雪崩快取穿透
- 快取穿透、快取雪崩、快取擊穿快取穿透
- 快取熱點,快取穿透,終極解決方案看過來快取穿透
- Redis快取穿透Redis快取穿透
- 一文讀懂快取穿透、快取擊穿、快取雪崩及其解決方案快取穿透
- 快取最佳化(快取穿透)快取穿透
- Redis快取擊穿、快取穿透、快取雪崩Redis快取穿透
- [Redis]快取穿透/快取擊穿/快取雪崩Redis快取穿透
- 快取穿透、快取擊穿、快取雪崩區別快取穿透
- Redis快取穿透/快取雪崩/快取擊穿(案例:產生的原因 解決方案利/弊)Redis快取穿透
- Redis系列 - 快取雪崩、擊穿、穿透及解決方案Redis快取穿透
- Redis快取穿透解決方案--布隆過濾器Redis快取穿透過濾器
- Redis詳解(十二)------ 快取穿透、快取擊穿、快取雪崩Redis快取穿透
- 面試總結 —— Redis “快取穿透”、“快取擊穿”、“快取雪崩”面試Redis快取穿透
- 快取穿透、快取雪崩和快取擊穿是什麼?快取穿透
- Redis——快取穿透、快取擊穿、快取雪崩、分散式鎖Redis快取穿透分散式
- Redis快取穿透、快取雪崩、快取擊穿好好說說Redis快取穿透
- 什麼是redis快取雪崩、快取穿透、快取擊穿Redis快取穿透
- 快取問題(一) 快取穿透、快取雪崩、快取併發 核心概念快取穿透
- Redis快取穿透和雪崩Redis快取穿透
- Redis快取穿透與雪崩Redis快取穿透
- Redis 快取擊穿、穿透、雪崩的原因以及解決方案Redis快取穿透
- 快取問題(四) 快取穿透、快取雪崩、快取併發 解決案例快取穿透
- Redis的快取穿透、快取雪崩、快取擊穿的區別Redis快取穿透
- 什麼是redis的快取雪崩與快取穿透Redis快取穿透
- Java高併發快取架構,快取雪崩、快取穿透之謎Java快取架構穿透