前言:在使用redis的時候,特別是大型應用,會碰到不少問題,下面就來總結一下使用redis時的常見問題
一、redis為緩存的問題
1、緩存和數據庫雙寫一致性問題
分析:一致性問題是分布式常見問題,還可以再分為最終一致性和強一致性。數據庫和緩存雙寫,就必然會存在不一致的問題。答這個問題,先明白一個前提。就是如果對數據有強一致性要求,不能放緩存。
我們所做的一切,只能保證最終一致性。另外,我們所做的方案其實從根本上來說,只能說降低不一致發生的概率,無法完全避免。因此,有強一致性要求的數據,不能放緩存。
回答:先淘汰cache,再寫db(如果刪除緩存失敗,那就不要更新數據庫,如果說刪除緩存成功,而更新數據庫失敗,那查詢的時候只是從數據庫里查了舊的數據而已,這樣就能保持數據庫與緩存的一致性。)
2、緩存雪崩、擊穿問題
請參考我的另一篇文章:緩存雪崩、擊穿解決方案
3、緩存的並發競爭問題
分析:這個問題大致就是,同時有多個子系統去set一個key。這個時候要注意什么呢?大家思考過么。需要說明一下,博主提前百度了一下,發現答案基本都是推薦用redis事務機制。
如果生產環境基本都是redis集群環境,做了數據分片操作。你一個事務中有涉及到多個key操作的時候,這多個key不一定都存儲在同一個redis-server上。因此,redis的事務機制,十分雞肋。
回答:
1、如果對這個key操作,不要求順序
這種情況下,准備一個分布式鎖,大家去搶鎖,搶到鎖就做set操作即可,比較簡單。
2、如果對這個key操作,要求順序
一般用串行方式就行,比如隊列
二、redis的過期策略及內存淘汰機制
這個問題其實相當重要,到底redis有沒用到家,這個問題就可以看出來。比如你redis只能存5G數據,可是你寫了10G,那會刪5G的數據。
怎么刪的,這個問題思考過么?還有,你的數據已經設置了過期時間,但是時間到了,內存占用率還是比較高,有思考過原因么?
1、redis采用的是定期刪除+惰性刪除策略。
2、為什么不用定時刪除策略?
定時刪除,用一個定時器來負責監視key,過期則自動刪除。雖然內存及時釋放,但是十分消耗CPU資源。在大並發請求下,CPU要將時間應用在處理請求,而不是刪除key,因此沒有采用這一策略.
3、定期刪除+惰性刪除是如何工作的呢?
定期刪除,redis默認每個100ms檢查,是否有過期的key,有過期key則刪除。需要說明的是,redis不是每個100ms將所有的key檢查一次,
而是隨機抽取進行檢查(如果每隔100ms,全部key進行檢查,redis豈不是卡死)。因此,如果只采用定期刪除策略,會導致很多key到時間沒有刪除。
於是,惰性刪除派上用場。也就是說在你獲取某個key的時候,redis會檢查一下,這個key如果設置了過期時間那么是否過期了?如果過期了此時就會刪除。
(1)上面提到的隨機抽取的方式
1、隨機測試100個設置了過期時間的key
2、刪除所有發現的已過期的key
3、若刪除的key超過25個則重復步驟1
說明:這是一個基於概率的簡單算法,基本的假設是抽出的樣本能夠代表整個key空間,redis持續清理過期的數據直至將要過期的key的百分比降到了25%以下。
另外每隔100ms檢測一次可以手動修改這頻率,可以找關於 hz 選項的說明。
注意:當REDIS運行在主從模式時,只有主結點才會執行上述這兩種過期刪除策略,然后把刪除操作”del key”同步到從結點。
4、采用定期刪除+惰性刪除就沒其他問題了么?
不是的,如果定期刪除沒刪除key。然后你也沒即時去請求key,也就是說惰性刪除也沒生效。這樣,redis的內存會越來越高。那么就應該采用內存淘汰機制。
在redis.conf中有一行配置:# maxmemory-policy volatile-lru
該配置就是配內存淘汰策略的
1)noeviction:當內存不足以容納新寫入數據時,新寫入操作會報錯。--不推薦。
2)allkeys-lru:當內存不足以容納新寫入數據時,在鍵空間中,移除最近最少使用的key。推薦使用。
3)allkeys-random:當內存不足以容納新寫入數據時,在鍵空間中,隨機移除某個key。--不推薦。
4)volatile-lru:當內存不足以容納新寫入數據時,在設置了過期時間的鍵空間中,移除最近最少使用的key。這種情況一般是把redis既當緩存,又做持久化存儲的時候才用。不推薦
5)volatile-random:當內存不足以容納新寫入數據時,在設置了過期時間的鍵空間中,隨機移除某個key。依然不推薦
6)volatile-ttl:當內存不足以容納新寫入數據時,在設置了過期時間的鍵空間中,有更早過期時間的key優先移除。不推薦
總結與備忘
1、如果Redis中每天過期大量Key(比如幾千萬),那么必須得考慮過期Key的清理:
1)、增加Redis主動清理的頻率(通過調大hz參數);
2)、手動清理過期Key,最簡單的方法是進行scan操作,scan操作會觸發第一種被動刪除,scan操作時候別忘了加count;
2、dbsize命令返回的Key數量,包含了過期Key;
3、randomkey命令返回的Key,不包含過期Key;
4、scan命令返回的Key,包含過期Key;
5、keys對應的Key數量等同於dbsize;
6、info命令返回的# Keyspace:db6:keys=1034937352,expires=994731489,avg_ttl=507838502
1)、expires指的是設置了過期時間的Key數量;
2)、avg_ttl指設置了過期時間的Key的平均過期時間(單位:毫秒);