一. 緩存穿透 (請求數據緩存大量不命中)
緩存穿透是指查詢一個一定不存在的數據,由於緩存不命中,並且出於容錯考慮, 如果從存儲層查不到數據則不寫入緩存,這將導致這個不存在的數據每次請求都要到存儲層去查詢,失去了緩存的意義。
例如:下圖是一個比較典型的cache-storage架構,cache(例如memcache, redis等等) + storage(例如mysql, hbase等等)架構,查一個壓根就不存在的值, 如果不做兼容,永遠會查詢storage.

1. 緩存空對象
(1). 定義:如上圖所示,當第②步MISS后,仍然將空對象保留到Cache中(可能是保留幾分鍾或者一段時間,具體問題具體分析),下次新的Request(同一個key)將會從Cache中獲取到數據,保護了后端的Storage。
public class XXXService { /** * 緩存 */ private Cache cache = new Cache(); /** * 存儲 */ private Storage storage = new Storage(); /** * 模擬正常模式 * @param key * @return */ public String getNormal(String key) { // 從緩存中獲取數據 String cacheValue = cache.get(key); // 緩存為空 if (StringUtils.isBlank(cacheValue)) { // 從存儲中獲取 String storageValue = storage.get(key); // 如果存儲數據不為空,將存儲的值設置到緩存 if (StringUtils.isNotBlank(storageValue)) { cache.set(key, storageValue); } return storageValue; } else { // 緩存非空 return cacheValue; } } /** * 模擬防穿透模式 * @param key * @return */ public String getPassThrough(String key) { // 從緩存中獲取數據 String cacheValue = cache.get(key); // 緩存為空 if (StringUtils.isBlank(cacheValue)) { // 從存儲中獲取 String storageValue = storage.get(key); cache.set(key, storageValue); // 如果存儲數據為空,需要設置一個過期時間(300秒) if (StringUtils.isBlank(storageValue)) { cache.expire(key, 60 * 5); } return storageValue; } else { // 緩存非空 return cacheValue; } } }
2. bloomfilter或者壓縮filter(bitmap等等)提前攔截
(1). 定義:如上圖所示,在訪問所有資源(cache, storage)之前,將存在的key用布隆過濾器提前保存起來,做第一層攔截, 例如: 我們的推薦服務有4億個用戶uid, 我們會根據用戶的歷史行為進行推薦(非實時),所有的用戶推薦數據放到hbase中,但是每天有許多新用戶來到網站,這些用戶在當天的訪問就會穿透到hbase。為此我們每天4點對所有uid做一份布隆過濾器。如果布隆過濾器認為uid不存在,那么就不會訪問hbase,在一定程度保護了hbase(減少30%左右)。
原文鏈接請參見:http://carlosfu.iteye.com/blog/2248185