2014-04-21 38 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

相关问题