雖然面對的是高併發場景,單今天只關注緩存,不討論線程安全和鎖相關的問題。
前言
日常工作中,時常要面對抽獎活動,獎勵發放,商品秒殺等大流量高併發的場景。
高併發場景面對的第一個問題是DB的IO瓶頸。 這時比較通用緩存方式是加一層redis,用內存的性能來解決IO的瓶頸。
但是引入Redis就一勞永逸了嘛?不是的,相對應的高併發場景又會引發Redis熱KEY和大KEY的問題,造成帶寬拉胯。
這時可以在做一層本地緩存。那麼問題又來了,本地緩存沒有過期時間啊,因此就可以用GUAVA CACHE來解決,本質上他就是封裝了一個過期時間,至於過期策略,一般有三種,定時刪除,定期刪除,惰性刪除,本地緩存,guava採用惰性刪除的方式就很合理。感興趣的同學,可以看下教程和源碼http://ifeve.com/google-guava,這裏不具體展開了。
附一張關鍵源碼圖:
場景與使用:
場景:動態配置獲取, 交易鏈路,需要獲取商家報名了活動,報名與否,會走不同的優惠策略。
首先要注意,爲防止緩存擊穿,我們不能依賴用戶請求來獲取配置,及時加鎖也不行,在交易鏈路使用分佈式鎖阻斷了交易就很坑。 所以,我們後臺起個TASK將數據跑入redis,緩存時間設置了3天防止過期。
private List<Long> getSignupSellerUids(Long sellerActivityId) {
// 報名商家sellerUid 本地緩存
List<Long> localSignedupUids =
signupUidsLocalCache.getIfPresent(AllowanceConstant.ALLOWANCE_SIGNEDUP_SELLERS_CACHE_KEY);
if (Validator.isNotNull(localSignedupUids)) {
return localSignedupUids;
}
// 本地沒命中 Redis緩存
String signedUpCacheKey = BeidianAllowanceCacheUtils.getSignedUpSellersCacheKey(sellerActivityId);
String confJsonStr = beidianRedisCacheClient.get(signedUpCacheKey);
List<Long> cacheSignedUids = Validator.isNotNullOrEmpty(JSON.parseArray(confJsonStr, Long.TYPE)) ?
JSON.parseArray(confJsonStr, Long.TYPE) :
Collections.emptyList();
if (!cacheSignedUids.isEmpty()) {
signupUidsLocalCache.put(AllowanceConstant.ALLOWANCE_SIGNEDUP_SELLERS_CACHE_KEY, cacheSignedUids);
return cacheSignedUids;
}
// 這裏已經是異常狀態了。
return Collections.emptyList();
}
一些會隨業務變化的動態配置,都非常適合使用多級緩存,讓你的程序穩穩當當喲~
沒有試過的小夥伴,一定要去試一試O(∩_∩)O