使用redis的原因
性能和并發(fā)
一.緩存穿透
緩存穿透的概念很簡單诅愚,用戶想要查詢一個數(shù)據(jù)缘挽,發(fā)現(xiàn)緩存沒有命中,于是向持久層數(shù)據(jù)庫查詢呻粹。發(fā)現(xiàn)也沒有壕曼,于是本次查詢失敗。當用戶很多的時候等浊,緩存都沒有命中腮郊,于是都去請求了持久層數(shù)據(jù)庫。這會給持久層數(shù)據(jù)庫造成很大的壓力筹燕,這時候就相當于出現(xiàn)了緩存穿透轧飞。
解決方案:
1.簡單校驗
因為有時候可能是攻擊者故意拿不存在的id攻擊,可以在接口處添加基礎(chǔ)校驗撒踪,對不可能出現(xiàn)的數(shù)據(jù)進行攔截过咬。
2.緩存空對象
從緩存取不到的數(shù)據(jù),在數(shù)據(jù)庫中也沒有取到制妄,這時也可以將key-value對寫為key-null掸绞,同時設(shè)置一個過期時間,也就是緩存有效時間耕捞,如30秒(設(shè)置太長會導(dǎo)致正常情況也沒法使用)衔掸。之后再訪問這個數(shù)據(jù)將會從緩存中獲取,保護了后端數(shù)據(jù)源俺抽;也可以防止攻擊用戶在短時間反復(fù)用同一個id暴力攻擊敞映。
但是這種方法會存在兩個問題:
1.如果空值能夠被緩存起來,這就意味著緩存需要更多的空間存儲更多的鍵磷斧,因為這當中可能會有很多的空值的鍵振愿;
2.即使對空值設(shè)置了過期時間,還是會存在緩存層和存儲層的數(shù)據(jù)會有一段時間窗口的不一致弛饭,這對于需要保持一致性的業(yè)務(wù)會有影響冕末。
3.布隆過濾器bloomfilter
當大量訪問不存在數(shù)據(jù)的請求到達時,先用布隆過濾器過濾孩哑,避免直接去查庫栓霜,也就是說布隆過濾器只能判斷數(shù)據(jù)是否一定不存在翠桦,而無法判斷數(shù)據(jù)是否一定存在横蜒。是有誤判率的問題的胳蛮。
二、緩存擊穿
某一個熱點 key丛晌,在緩存過期的一瞬間仅炊,同時有大量的請求打進來,由于此時緩存過期了澎蛛,所以請求最終都會走到數(shù)據(jù)庫抚垄,造成瞬時數(shù)據(jù)庫請求量大、壓力驟增谋逻,甚至可能打垮數(shù)據(jù)庫呆馁。
解決方案:
1.互斥鎖
在并發(fā)的多個請求中,只有第一個請求線程能拿到鎖并執(zhí)行數(shù)據(jù)庫查詢操作毁兆,其他的線程拿不到鎖就阻塞等著浙滤,等到第一個線程將數(shù)據(jù)寫入緩存后,直接走緩存气堕。
簡化代碼如下:
這里用到了JVM鎖:ReentrantLock纺腊。
分布式中一般會使用redis實現(xiàn)分布式鎖。
單臺服務(wù)器時也可以考慮用JVM鎖茎芭,JVM 鎖保證了在單臺服務(wù)器上只有一個請求走到數(shù)據(jù)庫揖膜,通常來說已經(jīng)足夠保證數(shù)據(jù)庫的壓力大大降低,同時在性能上比分布式鎖更好梅桩。
2.熱點數(shù)據(jù)不過期
三壹粟、緩存雪崩
緩存雪崩是指,就是在某一個時刻宿百,緩存集大量失效煮寡。所有流量直接打到數(shù)據(jù)庫上,對數(shù)據(jù)庫造成巨大壓力犀呼;
解決方案:
1.redis高可用
緩存數(shù)據(jù)庫是分布式部署幸撕,將熱點數(shù)據(jù)均勻分布在不同搞得緩存數(shù)據(jù)庫中。
2.限流降級
這個解決方案的思想是外臂,在緩存失效后坐儿,通過加鎖或者隊列來控制讀數(shù)據(jù)庫寫緩存的線程數(shù)量。比如對某個key只允許一個線程查詢數(shù)據(jù)和寫緩存宋光,其他線程等待貌矿。但是這種方式響應(yīng)會很慢
4.數(shù)據(jù)預(yù)熱
數(shù)據(jù)加熱的含義就是在正式部署之前,我先把可能的數(shù)據(jù)先預(yù)先訪問一遍罪佳,這樣部分可能大量訪問的數(shù)據(jù)就會加載到緩存中逛漫。在即將發(fā)生大并發(fā)訪問前手動觸發(fā)加載緩存不同的key,設(shè)置不同的過期時間赘艳,讓緩存失效的時間點盡量均勻酌毡。
4.緩存過期時間設(shè)置
緩存數(shù)據(jù)的過期時間設(shè)置隨機克握,防止同一時間大量數(shù)據(jù)過期現(xiàn)象發(fā)生〖咸ぃ或者直接設(shè)置熱點數(shù)據(jù)永遠不過期菩暗。