如何自动从Redis中的集合中删除过期的密钥?

时间:2015-09-28 19:27:25

标签: redis

我在Redis数据库中有4个密钥。密钥从现在开始有效期为10秒。我已经将钥匙添加到了一套。当密钥到期时,它们实际上不再在数据库中(get返回null值)。但是,键仍然是该组的成员。该集将继续存在,直到从集合中删除密钥,此时它从数据库中消失得太有效。

当密钥到期时,是否可以自动从其所属的集合中删除密钥?

我正在考虑维护每个密钥一组以维护它所属的集合(在密钥和集合之间建立有向图集关系),然后注册密钥到期事件以在必要时删除集合成员。作为db的使用者,这是一个很大的开销,而不是作为某种后台清理线程。而且,这种方法对于清理集合来说是“尽力而为”,因为订阅到期事件的消费者代码可能会崩溃,无法获取通知,积压等等。

我可以通过将密钥集建模为哈希集中的字段来避免任何欺骗,但我希望在实践中每个密钥具有不同的到期TTL。如果可能,那怎么回事?

例如,这是我的“foo”键集。

mine:0>set foo1 barA
OK

mine:0>set foo2 barB
OK

mine:0>set foo3 barC
OK

mine:0>set foo4 barD
OK

可以将它们添加到一组中。

mine:0>sadd foo foo1 foo2 foo3 foo4
4

mine:0>smembers foo
1) foo1
2) foo3
3) foo4
4) foo2

密钥可能会过期......

mine:0>expire foo1 10
1

mine:0>expire foo2 10
1

mine:0>expire foo3 10
1

mine:0>expire foo4 10
1

mine:0>get foo1 
NULL

mine:0>get foo2
NULL

mine:0>get foo3
NULL

mine:0>get foo4
NULL

mine:0>get foo5
NULL

此时键不存在,但是设置确实存在,并且它引用了键。

mine:0>smembers foo
1) foo1
2) foo3
3) foo4
4) foo2

显式删除密钥会将其从集合中删除,然后在删除所有密钥后使其不存在。

mine:0>srem foo foo1
1

mine:0>srem foo foo2
1

mine:0>srem foo foo3
1

mine:0>srem foo foo4
1

mine:0>smembers foo
[nothing returned]

1 个答案:

答案 0 :(得分:1)

很简单!

首先,我想指出redis中的数据没有任何参考关系! foo1作为键,foo1作为集合中的元素是两个不同的东西,不同的内存地址中的不同数据,恰好存储相同的字符串“foo1”。

其次,我的方式不需要改变你的数据模型,只需要你查询你的集合的方式。查询集合中的元素时,检查密钥是否也作为redis中的单独密钥存在,逻辑如下:

ArrayList getUnexpiredElementsInSet(String setKey){
            ArrayList elements = smembers(setKey);
            ArrayList resultArray = new ArrayList();
            for (element in elements) {
                if (exists(element)==false) {
                    srem(setKey, element);
                }else {
                    resultArray.add(element);
                }
            return resultArray;
          }

通过这种方式,当您想要查询集合中的内容时,您只会获得未过期的元素,并且还会清除过期的元素。

上面只是伪java代码,向您展示基本逻辑,您需要将此逻辑包装在lua事务中。如果你不了解redis的lua功能,那就去学习吧!它很棒,让redis超级快速而强大。如果你想利用redis的真正力量,lua是不可或缺的!请参阅Redis Lua

有些人担心脚本命令的性能损失。我可以向你保证这是不必要的。根据官方文档和我在实践中所经历的,运行脚本根本没有性能损失。 从理论上讲,这在很多方面都是可以理解的

  1. Redis采用Lua而不是任何其他语言,因为Lua声称是最快的脚本语言。
  2. 每个脚本都可以存储在服务器端,并且可以由客户端仅发送该脚本的sha1值及其输入参数来调用,因此不存在长脚本的I / O负担。
  3. 通过发送存储脚本的sha1运行脚本时,脚本在redis服务器上预编译。因此,以这种方式,运行包含在脚本中的命令与以旧的形式运行这些命令基本相同,除了脚本节省了大量耗时的I / O操作。难怪它超级快。