善待Redis里的數據
Redis為我們提供便利的同時,我們也要善待里面的數據
</blockquote>Redis是我們數據的保管者,我們可以隨時存隨時取,大的小的,重要的不重要的,它都毫無怨言的幫我們保存著,甚至有些時候,我們變得很懶,存東 西進去的時候順便還貼張紙:“過了一個星期就幫我扔了吧”,對于這些,Redis也都默默的接受了(誰叫Antirez把redis設計的這么好呢)。
這次要寫的就是關于這張留言紙的事。
Redis提供了一套“美好”的過期數據清理機制:
主動過期: Redis對數據是惰性過期,當一個key到了過期時間,Redis也不會馬上清理,但如果這個key過期后被再次訪問,Redis就會主動將它清理掉。
</li>被動過期: 如果過期的Key一直沒被訪問,Redis也不會一直把它放那不管,它會每秒10次的執行以下的清理工作:
- 隨機從所有帶有過期時間的Key里取出20個
- 如果發現有過期的,就清理
- 如果這里有25%的Key都是過期的,就繼續回到第一步再來一次
</ul> </li> </ul>這套過期機制設計的很贊,可以這樣理解:如果當前有超過1/4的Key是過期的話,就不停地清理,直到只剩下1/4不到的Key是要過期的為止,然后就慢慢地隨機抽查著清理。
現在我們再說說對待Redis數據的姿勢問題。
先看一個現象,某段程序每天24小時的跑著,但時不時地出現拿不到連接的錯誤:
Caused by: redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool ... Caused by: java.util.NoSuchElementException: Unable to validate object
這個錯誤是因為JedisPool拿到一個連接后,調用jedis.ping()方法沒有得到正確的返回”pong”消息,而出現這個問題時,并不是traffic的高峰期,redis的cpu不高,于是程序員很快就懷疑到網絡上,難道有”丟包”?
但跑了幾天,發現出錯的時間固定在某幾個時間點(如晚上9點~10點),莫非是掃地阿姨每天定時在機房打掃衛生,碰著網線了?(有時候不得不佩服程序員的想象力)
然而在一個夜黑風高的晚上,程序員的腦子在這個時候一般是最清醒的,這時告警短信又來了,打開redis監控,像在唯品會上逛街一樣,對著 redis的各項監控數據逛啊逛,突然,看到有幾條Expires的數據,當時的表情只能用看到關注了幾天的商品上標了大大”0.1折”時的表情來形容。
接下來的事情,想必大家也都猜到個七七八八了,當然是下單搶購支付了,腦子里一系列的運算,掐指一算: “這個時間點正好有一大批key過期”,而且都是大的Set集合,每個都有幾十萬的數據,再一算: “Redis里的大部分需要過期的key就是這些key”。
于是,答案有了,Redis進行被動過期清理時,發現怎么隨機,都有超過1/4的Key都是過期的,就忙著不停的刪啊刪,再加上又都是大集合的刪除,O(N)的操作復雜度,無奈,等redis刪完時,客戶端那邊的命令都等超時了。
原因找到了,如何解決?看業務場景吧,對于我們的場景,做法是將過期時間設長一點,然后把這些可以刪掉的Key標記一下,丟到一個后臺線程那里分頁刪Set里的數據,這樣就算redis再做過期操作,也不會用太多的時間來刪除。
最后,稍稍總結下,對于大個的集合對象,放redis的時候需要額外注意,如果想依賴redis的過期,可能會造成過期時短暫的redis block。
所以,要善待redis數據,比如不用了就自己清理掉,不要等著redis來幫你。
來自:http://neway6655.github.io/redis/2015/12/19/善待Redis里的數據.html
![]()