我希望在我的redis存储中挥发性密钥到期时收到通知。redis网站提供了一些关于如何在http://redis.io/topics/notifications中实现这一目标的描述,但我想知道它是否可以使用python redis api完成。
在我的redis.conf文件中设置:notify-keyspace-events Ex
后
并将其作为测试运行:
import redis
import config
client = redis.StrictRedis.from_url(config.REDIS_URI)
client.set_response_callback('EXPIRE',callback)
client.set('a', 1)
client.expire('a',5)
callback()
只在client.expire('a',5)
被调用时被调用,而不是像预期的那样晚5秒被调用
令人惊讶的是(当键的存活时间达到零时没有看到过期事件)与Python无关,而是与Redis正在过期键的方式有关。
Redis doc on Timing of expired events
过期事件计时
有生存时间的键被Redis以两种方式过期:
- 当命令访问该密钥时,发现该密钥已过期。
- 通过后台系统在后台查找过期的密钥,增量,以便能够收集从未访问过的密钥。
当一个key被访问并且被上面的一个系统发现已经过期时,就会产生过期事件,因此不能保证Redis服务器能够在key的有效时间达到0的时候产生过期事件。
如果没有命令持续地针对键,并且有许多键与TTL相关联,则在键的存活时间降为零和生成过期事件的时间之间可能会有明显的延迟。
基本上过期事件是在Redis服务器删除key时产生的,而不是在理论上存活时间达到零时产生的。
控制台小测试
当Redis运行时($ sudo service redis-server start
)
我启动了一个控制台并订阅了:
$ redis-cli
PSUBSCRIBE "__key*__:*"
然后,在另一个控制台中:
$ redis-cli
> config set notify-keyspace-events AKE
什么应该订阅各种事件
然后我在第二个控制台继续实验:
> set aaa aaa
> del aaa
> set aaa ex 5
> get aaa
在订阅的控制台中可以看到所有的活动。只是密钥过期有时会延迟几秒钟,有时会及时到来。
请注意,消息之间存在微妙的差异,一个消息 __keyevent@0__:expire
另一个消息 __keyevent@0__:expired
。
示例侦听器spy.py
import redis
import time
r = redis.StrictRedis()
pubsub = r.pubsub()
pubsub.psubscribe("*")
for msg in pubsub.listen():
print time.time(), msg
此代码在默认redis中注册到所有现有通道,并打印发布的内容。
运行:$ python spy.py
和在另一个控制台中尝试设置一个带有过期的密钥。你会看到所有的事件。
用于跟随redis-cli输入。
$ redis-cli
127.0.0.1:6379> set a aha
OK
127.0.0.1:6379> set b bebe ex 3
OK
127.0.0.1:6379> set b bebe ex 3
OK
我们得到spy输出:
1401548400.27 {'pattern': None, 'type': 'psubscribe', 'channel': '*', 'data': 1L}
1401548428.36 {'pattern': '*', 'type': 'pmessage', 'channel': '__keyspace@0__:a', 'data': 'set'}
1401548428.36 {'pattern': '*', 'type': 'pmessage', 'channel': '__keyevent@0__:set', 'data': 'a'}
1401548436.8 {'pattern': '*', 'type': 'pmessage', 'channel': '__keyspace@0__:b', 'data': 'set'}
1401548436.8 {'pattern': '*', 'type': 'pmessage', 'channel': '__keyevent@0__:set', 'data': 'b'}
1401548436.8 {'pattern': '*', 'type': 'pmessage', 'channel': '__keyspace@0__:b', 'data': 'expire'}
1401548436.8 {'pattern': '*', 'type': 'pmessage', 'channel': '__keyevent@0__:expire', 'data': 'b'}
1401548439.82 {'pattern': '*', 'type': 'pmessage', 'channel': '__keyspace@0__:b', 'data': 'expired'}
1401548439.82 {'pattern': '*', 'type': 'pmessage', 'channel': '__keyevent@0__:expired', 'data': 'b'}
1401548484.46 {'pattern': '*', 'type': 'pmessage', 'channel': '__keyspace@0__:b', 'data': 'set'}
1401548484.46 {'pattern': '*', 'type': 'pmessage', 'channel': '__keyevent@0__:set', 'data': 'b'}
1401548484.46 {'pattern': '*', 'type': 'pmessage', 'channel': '__keyspace@0__:b', 'data': 'expire'}
1401548484.46 {'pattern': '*', 'type': 'pmessage', 'channel': '__keyevent@0__:expire', 'data': 'b'}
1401548487.51 {'pattern': '*', 'type': 'pmessage', 'channel': '__keyspace@0__:b', 'data': 'expired'}
1401548487.51 {'pattern': '*', 'type': 'pmessage', 'channel': '__keyevent@0__:expired', 'data': 'b'}