1. 程式人生 > >善待Redis裡的資料

善待Redis裡的資料

又是一篇關於姿勢的文章,為什麼是”又”呢?因為上個星期剛寫完一篇關於Apache Commons Pool的正確使用姿勢的文章,點選此處閱讀。

Redis為我們提供便利的同時,我們也要善待裡面的資料

Redis是我們資料的保管者,我們可以隨時存隨時取,大的小的,重要的不重要的,它都毫無怨言的幫我們儲存著,甚至有些時候,我們變得很懶,存東西進去的時候順便還貼張紙:“過了一個星期就幫我扔了吧”,對於這些,Redis也都默默的接受了(誰叫Antirez把redis設計的這麼好呢)。

這次要寫的就是關於這張留言紙的事。

Redis提供了一套“美好”的過期資料清理機制:

  • 主動過期: Redis對資料是惰性過期,當一個key到了過期時間,Redis也不會馬上清理,但如果這個key過期後被再次訪問,Redis就會主動將它清理掉。

  • 被動過期: 如果過期的Key一直沒被訪問,Redis也不會一直把它放那不管,它會每秒10次的執行以下的清理工作:

    • 隨機從所有帶有過期時間的Key裡取出20個
    • 如果發現有過期的,就清理
    • 如果這裡有25%的Key都是過期的,就繼續回到第一步再來一次

這套過期機制設計的很贊,可以這樣理解:如果當前有超過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來幫你。

image

原文地址:http://neway6655.github.io/redis/2015/12/19/%E5%96%84%E5%BE%85Redis%E9%87%8C%E7%9A%84%E6%95%B0%E6%8D%AE.html?utm_source=tuicool&utm_medium=referral