您好,登錄后才能下訂單哦!
本篇文章給大家分享的是有關Redis的使用方法是怎么樣的,小編覺得挺實用的,因此分享給大家學習,希望大家閱讀完這篇文章后可以有所收獲,話不多說,跟著小編一起來看看吧。
使用Redis做K-V存儲,一定要注意過期時間的把控,任何K-V的存儲都要設置過期時間,不管多長時間。一般在封裝Redis操作工具類時提供默認使用系統公共超時時間的操作API,避免新手在使用時不設置過期時間,導致內存的浪費。另外,通過連接池 Jedis jedis = JedisPool.getResource();
這樣獲取Redis連接最好使用try/finally
塊,并且在finally塊中調用 jedis.close()
; 將連接歸還給連接池,否則將會一直持有連接,很有可能導致在將來的某一時刻報拿不到連接的錯。這也是之前某一個同事犯過的錯導致生產bug!
你以為Redis做緩存就萬無一失嗎?就單純的遵循那種經典操作嗎?(即:請求來了,先看緩存有沒有,有直接返回,沒有就查數據庫,數據庫有的話先存緩存,然后返回,數據庫沒有就返回空)這樣就是Redis緩存的正確姿勢嗎?如果你這樣做,很可能疏忽一點,那就是緩存穿透。如之前在項目中做的一個需求-頁面廣告可配置化自動上下線(我在之前專門寫過一篇文章介紹這個需求的一步步演進過程,對Redis新手很有幫助,感興趣的可以去看看),簡單的提一下吧,就是比如在支付完成的頁面大家都應該見過吧,比如支付完成后的結果頁,可能會彈出來一個紅包什么的,頁面下方的廣告位等,就是類似的這樣一個需求。因為這個頁面訪問量很大,進這個頁面就查這個廣告位的數據,當運營最近不想配置廣告了,這邊查到的是不是就是是空啊?數據庫也是空的,緩存也沒有數據,那很多請求都來,這樣就平白無故的造成了數據庫的壓力呀,多么的浪費!如果是別的其他業務,黑客鉆了空子,專門請求你系統根本不存在的數據,請求多了,都打到數據庫,是很有可能把你數據庫打死的。如果你在做需求的時候沒想到這一點,那后續出了問題,你就等著背鍋了。
怎么避免呢?
好辦,可以將數據庫也不存在的數據存個null值或一個空json(總之你自己約定好就行),也給放到Redis里,設置個較短的過期時間,下次再來取的時候看到是空就直接返回。另外,可以使用布隆過濾器做一層系統級的防護,專門去攔截系統中根本不存在的key。
剛說完緩存穿透,再聊聊緩存雪崩。比如你將用戶數據放到緩存里,當某一時刻這些數據全部都過期了,大量請求都過來,發現緩存無法命中,不就都去數據庫了嗎,數據庫一下子來這么多請求不就搞掛了嗎?解決辦法就是盡量是key的過期時間分散開,不要集中。在一個固定的過期時間上+一個隨機值,比如你設置的過期時間是5小時,你可以加一個0-600秒的隨機值。
緩存失效時多個請求同時請求同一個key,都發現緩存中空了,都去查數據庫,這不是浪費嗎,正常一個去查就行了,查完放緩存別的請求直接從緩存拿就行了。這就是緩存并發問題。當請求非常的多的時候,會對數據庫造成很大的沖擊,也是有可能把數據庫搞掛的吧?怎么解決,可以對更新緩存的操作加鎖,使用synchronized嗎?不行,因為生產上是分布式部署的,需要使用redis分布式鎖。
例如,當緩存數據失效的時候,某一線程使用資源ID作為key嘗試加分布式鎖,加鎖成功的線程執行更新緩存的操作將查到的數據放入緩存緩存中,其他線程就可以直接使用緩存數據了。
正如上面所說,在集群部署的情況下synchronized就失效了,所以分布式鎖就派上用場了。常見的分布式鎖的實現方式有三種:基于數據庫,基于Redis,基于Zookeeper。
Redis分布式鎖需要特別注意的點就是鎖的過期時間,如,使用redis的setnx命令,設置成功即表示拿到鎖,然后設置過期時間,命令執行失敗的線程表示獲取鎖失敗。一定要注意鎖的過期時間的設置,有加鎖的操作,也要有解鎖的操作。如之前我們項目的一個臨時性的一個組團競走的活動,10人成團競走PK的活動,在組團階段,用戶可以邀請朋友加入自己的團。我們的團數據是存放在Redis中的,包括每個團的人數。當用戶發起入團操作時,后臺邏輯會從redis取該團的現有成員數,如果小于10才能繼續走下面的邏輯。當并發場景下,如團長分享給很多人入團邀請,這些人的入團請求并發執行的情況下很有可能能造成組團人數超過10人的情況。因為在并發場景下,執行獲取當前團成員數的這行代碼會被多個請求獲取到,比如臨界的時候,團成員已經有了9個,同時來了倆入團請求,如果不加控制,同時執行讀取現有團成員個數時都讀到的是9,然后都執行入團操作,就會造成團成員超過10人的bug。
所以在入團請求的邏輯上,要加分布式鎖,獲取到鎖才能執行后續邏輯。因為獲取鎖的操作是使用setnx命令,并沒有等待鎖的機制,我們需要在獲取鎖的邏輯加一個自旋,每隔一定時間嘗試一次獲取,超過一定時間后返回加鎖失敗。
public boolean tryLock(String lockKey,long expireTime){ long waitTime = 0; //setIfAbsent使用的是redis的setnx方法 boolean success = redisTemplate.opsForValue().setIfAbsent(lockKey,"jingzouLock", expireTime,TimeUnit.MILLISECONDS); if(success==true){ return success; }else{ while(success==false && waitTime <50000L){ success = redisTemplate.opsForValue().setIfAbsent(lockKey,"jingzouLock", expireTime, TimeUnit.MILLISECONDS); try{ Thread.sleep(100); }catch(Exception e){} waitTime+=100L; } } return success;}
另外,還需要遵循“解鈴還須系鈴人”的原則,誰加的鎖誰解,不然自己加的鎖,被別人解了也是會造成問題的。例如,用戶A,請求入團,拿到分布式鎖,如果A因為某些原因在鎖超時時間內沒有執行完代碼,鎖就過期自動釋放了,如果此時B請求加入同一個團,拿到了分布式鎖,如果此時A請求執行完了,釋放鎖了,但是釋放的是B的鎖,這樣也有可能造成團人數超過10的bug。所以,設置分布式鎖時的value可以設置成不同的值,如A請求是用戶ID為12的用戶,設置分布式鎖的時候就value就可以用這個唯一的元素,當解鎖的時候再驗證value是12時才能執行解鎖操作。
如上加鎖代碼,我們增加一個參數String value傳入動態值,在上述場景中可以用用戶ID,代替我們寫死的"jingzouLock"。然后在釋放鎖的方法里,我們先判斷value值,相同再執行刪除。
public void releaseLock(String lockKey,String value){ String valueInRedis = redisTemplate.get(lockKey); if(value.equals(valueInRedis)){ redisTemplate.delete(lockKey); }}
還有一種場景需要考慮。當Redis master發生故障,主備切換時往往會造成數據丟失,包括分布式鎖的Key-Value。這樣就會導致鎖間接的被釋放了,假如操作還沒執行完,鎖被其他請求拿到了,分布式鎖就起不到作用了。
考慮到這方面的問題,Redis官方提供了Redlock算法,以及相應的開源實現Redisson。用到分布式鎖的場景,大家可以直接使用 Redisson,非常方便,后期可能會寫一寫Redisson的技術干貨。
另外,如果系統對可靠性要求很高,如需用到分布式鎖,建議使用分布式鎖的另外實現方式,如:Zookeeper,etcd等。
以上就是Redis的使用方法是怎么樣的,小編相信有部分知識點可能是我們日常工作會見到或用到的。希望你能通過這篇文章學到更多知識。更多詳情敬請關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。