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

如何在Redis中自动从集合中删除过期密钥?,redis,Redis,比如说,我在Redis数据库中有4个键。从现在起,这些钥匙的有效期为10秒。我已将钥匙添加到一组中。当密钥过期时,它们实际上不再存在于数据库中(get返回null值)。但是,这些键仍然是集合的成员。该集合将继续存在,直到密钥从集合中删除,此时它也将从数据库中有效地删除 密钥过期时,是否可以自动从其所属的集合中删除密钥 我正在考虑为每个密钥维护一个集合,以维护它所属的集合(在密钥和集合之间建立有向图集合关系),然后注册密钥过期事件,以便在必要时删除集合成员。作为db的消费者,这是一个很大的开销,而

比如说,我在Redis数据库中有4个键。从现在起,这些钥匙的有效期为10秒。我已将钥匙添加到一组中。当密钥过期时,它们实际上不再存在于数据库中(get返回null值)。但是,这些键仍然是集合的成员。该集合将继续存在,直到密钥从集合中删除,此时它也将从数据库中有效地删除

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

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

通过将密钥集建模为散列集中的字段,我可能能够避免任何欺骗,但实际上我希望每个密钥具有不同的过期TTL。如果这是可能的,那怎么可能呢

例如,这是我的一组“foo”键

它们可以添加到集合中

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]
很简单

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

第二,我的方法不需要更改数据模型,只需要更改查询集合的方法。查询集合中的元素时,检查该键在redis中是否也作为单独的键存在,逻辑如下:

ArrayList getUnexpiredElementsInSet(字符串设置键){
ArrayList元素=smembers(设置键);
ArrayList resultArray=新的ArrayList();
for(元素中的元素){
如果(存在(元素)=false){
srem(设置键,元素);
}否则{
resultArray.add(元素);
}
返回结果数组;
}
这样,当您想要查询集合中的内容时,您只会得到未过期的元素,并且过期的元素也会被清除

以上只是伪java代码,向您展示基本逻辑,您需要将此逻辑封装在lua事务中。如果您不知道redis的lua功能,请学习它!它很棒,让redis超级快速和强大。如果您想利用redis的真正功能,lua是不可或缺的!请参阅

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

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

  • 为什么不在集合上设置一个过期时间,与添加到集合中的键相同或最小/最大?这很好。关于键和集合成员在物理上是不同的数据段,这一点非常好。这是问题的核心。使用获取未过期成员并删除过期成员的方法,集合可能会继续运行如果在所有密钥过期后不使用它们,则它们将永远存在。因此,为了确保内存增长是有限制的,需要定期检查每个集合。私下里,我希望有人能够将lua脚本作为事件挂钩在服务器上运行。尽管据我所知,运行脚本会带来很大的性能损失。
    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]