我需要过期的所有密钥在重新散列,这是一个月以上。
这是不可能的 ,为了 让 Redis 保持简单。
雷迪斯的创始人安提雷斯说:
嗨,这是不可能的,要么使用不同的顶级关键 特定字段,或者与所归档的另一个字段一起存储 过期时间,同时获取这两个属性,并让应用程序理解 基于当前时间仍然有效或无效。
你可以。这里有一个例子。
redis 127.0.0.1:6379> hset key f1 1 (integer) 1 redis 127.0.0.1:6379> hset key f2 2 (integer) 1 redis 127.0.0.1:6379> hvals key 1) "1" 2) "1" 3) "2" redis 127.0.0.1:6379> expire key 10 (integer) 1 redis 127.0.0.1:6379> hvals key 1) "1" 2) "1" 3) "2" redis 127.0.0.1:6379> hvals key 1) "1" 2) "1" 3) "2" redis 127.0.0.1:6379> hvals key
使用 过期或 过期命令。
如果您想使散列中的特定键过期超过1个月。这是不可能的。 Redis 过期命令适用于散列中的所有键。 如果设置每日散列密钥,则可以设置密钥的生存时间。
hset key-20140325 f1 1 expire key-20140325 100 hset key-20140325 f1 2
有一个 Redissonjava 框架,它实现带有条目 TTL 支持的散列 Map对象。它在引擎盖下使用 hmap和 zset Redis 对象。用法例子:
Map
hmap
zset
RMapCache<Integer, String> map = redisson.getMapCache('map'); map.put(1, 30, TimeUnit.DAYS); // this entry expires in 30 days
这种方法非常有用。
关于 NodeJS 实现,我在 HASH 中保存的对象中添加了一个自定义 expiryTime字段。然后,在一段特定的时间后,我使用以下代码清除过期的 HASH 条目:
expiryTime
client.hgetall(HASH_NAME, function(err, reply) { if (reply) { Object.keys(reply).forEach(key => { if (reply[key] && JSON.parse(reply[key]).expiryTime < (new Date).getTime()) { client.hdel(HASH_NAME, key); } }) } });
你可以用不同的方式在 Redis 存储键/值,只需在存储键时添加一个前缀或名称空间,例如“ hset _”
获取一个键/值 GET hset_key等于 HGET hset key
GET hset_key
HGET hset key
将键/值 SET hset_key value等于 HSET hset key
SET hset_key value
HSET hset key
获取所有键 KEYS hset_*等于 HGETALL hset
KEYS hset_*
HGETALL hset
获取所有的 val 应该在2个操作中完成,首先获取所有键 KEYS hset_*,然后获取每个键的值
用 TTL 或过期添加键/值,这是问题的主题:
SET hset_key value EXPIRE hset_key
注意 : KEYS将在整个数据库中查找匹配的键,这可能会影响性能,特别是如果您有大型数据库。
KEYS
注:
KEYS将在整个数据库中查找匹配的键,这可能会影响性能,特别是如果您有大的数据库。虽然 SCAN 0 MATCH hset_*可能更好,只要它不阻塞服务器,但仍然是一个问题的情况下,大型数据库。
SCAN 0 MATCH hset_*
您可以创建一个新的数据库来分别存储这些您希望过期的密钥,特别是如果它们是一小组密钥的话。
感谢@DanFarrell 强调了与 KEYS
您可以使用 psubscribe和 "__keyevent@<DB-INDEX>__:expired"来使用 Redis Keyspace 通知。
psubscribe
"__keyevent@<DB-INDEX>__:expired"
这样,每次密钥过期时,都会在 Redis 连接上发布一条消息。
关于您的问题,基本上您创建了一个临时的“正常”键使用 set与过期时间在 s/ms 它应该匹配的名称,您希望删除的关键在您的集合。
set
由于您的临时密钥将在 "__keyevent@0__:expired"过期时发布到您持有 "__keyevent@0__:expired"的 Redis 连接上,因此您可以轻松地从原始集中删除密钥,因为消息中将包含密钥的名称。
"__keyevent@0__:expired"
该页面中的一个简单实践例子: https://medium.com/@micah1powell/using-redis-keyspace-notifications-for-a-reminder-service-with-node-c05047befec3
Doc: https://redis.io/topics/notifications(查找标志 xE)
您可以在 reis 中使用 分类设置来获得一个以时间戳作为得分的 TTL 容器。 例如,无论何时向集合中插入事件字符串,都可以将其分数设置为事件时间。 因此,您可以通过调用 zrangebyscore "your set name" min-time max-time
zrangebyscore "your set name" min-time max-time
而且,我们可以通过使用 zremrangebyscore "your set name" min-time max-time来删除旧的事件来做到过期。
zremrangebyscore "your set name" min-time max-time
这里唯一的缺点是您必须从外部流程进行内部管理,以保持集合的大小。
Redis 不支持将 TTL放在除顶键以外的散列上,因为顶键会使整个散列过期。如果您正在使用分片集群,则可以使用另一种方法。这种方法不可能在所有场景中都有用,并且性能特征可能与预期的不同。值得一提的是:
TTL
当有一个散列时,结构基本上是这样的:
hash_top_key - child_key_1 -> some_value - child_key_2 -> some_value ... - child_key_n -> some_value
因为我们要将 TTL添加到子键,所以可以将它们移动到顶键。主要的一点是,现在的密钥应该是 hash_top_key和子密钥的组合:
hash_top_key
{hash_top_key}child_key_1 -> some_value {hash_top_key}child_key_2 -> some_value ... {hash_top_key}child_key_n -> some_value
我们是有意使用 {}表示法的。这允许所有这些键落在同一个 hash slot中。你可以在这里了解更多: https://redis.io/topics/cluster-tutorial
{}
hash slot
现在,如果我们想对散列执行相同的操作,我们可以这样做:
HDEL hash_top_key child_key_1 => DEL {hash_top_key}child_key_1 HGET hash_top_key child_key_1 => GET {hash_top_key}child_key_1 HSET hash_top_key child_key_1 some_value => SET {hash_top_key}child_key_1 some_value [some_TTL] HGETALL hash_top_key => keyslot = CLUSTER KEYSLOT {hash_top_key} keys = CLUSTER GETKEYSINSLOT keyslot n MGET keys
这里有趣的是 HGETALL。首先,我们得到的 hash slot为我们所有的子密钥。然后我们得到特定 hash slot的键,最后我们检索这些值。我们需要在这里小心,因为可能有更多的 n键为该 hash slot,也可能有键,我们不感兴趣,但他们有相同的 hash slot。我们实际上可以编写一个 Lua脚本,通过执行 EVAL或 EVALSHA命令在服务器中执行这些步骤。同样,您需要考虑这种方法在特定场景中的性能。
HGETALL
n
Lua
EVAL
EVALSHA
更多参考资料:
我们在这里讨论过同样的问题。
我们有一个 Redis 散列,它是散列条目(名称/值对)的键,我们需要在每个散列条目上保存各个过期时间。
我们通过添加 n 个字节的前缀数据来实现这一点,这些数据包含编码的过期信息,当我们写入散列条目值时,我们还将键设置为在写入值时包含过期信息。
然后,在读取时,我们解码前缀并检查是否过期。这是额外的开销,但是,读仍然是 O (n) ,并且当最后一个散列条目过期时,整个密钥将过期。
这是可能的在 KeyDB,这是一个分叉的红色。因为它是一个叉子它完全兼容的 Redis 和工程作为一个下降的替代品。
只需使用 EXPIREMEMBER 命令,它可以处理集合、散列和排序集合。
EXPIREMEMBER keyname subkey [ time ]
您还可以使用 TTL 和 PTTL 查看过期
TTL 键名子键
这里有更多的文档: https://docs.keydb.dev/docs/commands/#expiremember
如果你的用例是在 Redis 缓存值,并且容忍过期的值,但是想要偶尔刷新它们,这样它们就不会过期,那么一个可行的解决方案就是在字段值中包含一个时间戳,然后在你访问该值的任何地方处理过期。
这使您可以正常地继续使用 Redis 散列,而无需担心其他方法可能引起的任何并发症。唯一的开销是客户端上的一点额外的逻辑和解析。这不是一个完美的解决方案,但这是我通常会做的,因为我不需要 TTL 的任何其他原因,而且我通常需要对缓存的值进行额外的解析。
基本上就是这样:
红迪斯:
hash_name - field_1: "2021-01-15;123" - field_2: "2021-01-20;125" - field_2: "2021-02-01;127"
您的(伪)代码:
val = redis.hget(hash_name, field_1) timestamp = val.substring(0, val.index_of(";")) if now() > timestamp: new_val = get_updated_value() new_timestamp = now() + EXPIRY_LENGTH redis.hset(hash_name, field_1, new_timestamp + ";" + new_val) val = new_val else: val = val.substring(val.index_of(";")) // proceed to use val
Imo 最大的警告是,永远不要删除字段,以便散列可以变得非常大。不知道是否有一个优雅的解决方案-我通常只是删除散列每隔一段时间,如果它觉得太大。也许您可以跟踪已经存储在某个地方的所有内容,并定期删除它们(尽管在这一点上,您可能只是使用该机制手动终止字段... ...)。
埃隆 · 马斯克很快就会把人类送上月球,而我们仍然不能让土地在重建中失效
不管怎样,我想到的解决办法是:
假设我想每3分钟过期一次: 所以我把数据保存在3个字段012中。 然后在几分钟内完成模块% 3到当前时间。
如果 example = = 0的模块 所以我只使用12和0 i 删除; 然后它变成1,所以 IM 使用2和0,并删除1。
我没有使用它,我没有检查它,但我只是让你知道它的可能性
static async setCount(ip: string, count: number) { const val = await redisClient.hSet(ip, 'ipHashField', count) await redisClient.expire(ip, this.expireTime) }
试试让你的钥匙过期。