2014-04-21 103 views
1

我有一個簡單的問題,是否有任何選項可以更彈性地使用redis.expire?

假設如果服務器在10分鐘內收到來自用戶的10條消息,服務器會發送推送電子郵件。

起初我以爲使用Redis的很簡單,

incr("foo"), expire("foo",60*10) 

,並在Java中,處理髮生次數像下面

if(jedis.get("foo")>=10){sendEmail();jedis.del("foo");} 

但想象一下,如果用戶在第一分鐘發送一條消息,併發送第10分鐘發送8條消息。

和密鑰過期,用戶再次在下一分鐘發送3個消息。

redis的密鑰將再次與值3被創建,其將不會觸發sendEmail(),即使用戶在2分鐘內發送11條消息實際上。

我們要使用Redis的,我們不希望把接收時間值的Redis。

有沒有解決方法?

回答

0

因此,有解決this--一個2種方式,以優化空間和其他優化速度(儘管真正的轉速差應該是邊際)。

優化空間:

保持多達9級不同的計數器; foo1 ... foo9。基本上,我們會在給用戶發送電子郵件之前爲每個可能的最多9個不同的消息保留一個計數器,並讓每個計數器在達到10分鐘時過期。這將像循環隊列一樣工作。現在這樣做(在Python爲簡單起見,假設我們要Redis的連接稱爲r):

new_created = False 
for i in xrange(1,10): 
    var_name = 'foo%d' % i 
    if not (new_created or r.exists(var_name)): 
     r.set(var_name, 0) 
     r.expire(var_name, 600) 
     new_created = True 
    if not r.exists(var_name): continue 
    r.incr(var_name, 1) 
    if r.get(var_name) >= 10: 
     send_email(user) 
     r.del(var_name) 

如果用這種方法去,把上面的邏輯在一個Lua腳本,而不是例如Python和它應該相當快。由於您最多可以爲每位用戶存儲9個計數器,因此它的空間效率也會相當高。

優化速度:

保持一個Redis的Sortet設置每個用戶。每當用戶發送消息時,使用等於時間戳和任意值的密鑰添加到他的排序集。然後,只要做一個ZCOUNT(now, now - 10 minutes)併發送一封電子郵件,如果它大於10。然後ZREMRANGEBYSCORE(now - 10 minutes, inf)。我知道你說過你不想在Redis中保留時間戳,但是IMO這是一個更好的解決方案,你將不得不在某個地方的某個時間戳上放置一些變體。

個人而言,我會用後一種方法去,因爲空間差異可能並不大,並且代碼可以迅速在純的Redis來完成,但取決於你。我沒有提到

+0

一件事是,所以我覺得第二個選項可能是一個更好的辦法,我會嘗試的時間間隔爲每一位用戶不同而不同。謝謝。 –

+0

@이승진是的,我認爲。對於第一種方法,這個想法是你每個用戶只有一個foo1 ... 9。只需將user_id附加到每一行,或沿着這些行的任何內容。無論如何,我同意第二種方法更好。讓我知道事情的後續。 – Eli

相關問題