【问题标题】:Finding non-expiring keys in Redis在 Redis 中查找未过期的键
【发布时间】:2012-03-22 07:18:56
【问题描述】:

在我的设置中,info 命令显示以下内容:

[keys] => 1128
[expires] => 1125

我想找到这 3 个没有过期日期的密钥。我已经检查了文档无济于事。有什么想法吗?

【问题讨论】:

  • 我不禁想知道其他到达这里的人是否这样做是因为getset 命令破坏了他们在密钥上的 TTL。这不是记录在案的事情,而是正在发生的事情。 getset 将被弃用,但这让我们很难受。

标签: redis


【解决方案1】:

@Waynn Lue 的答案运行但使用了 Redis warns about 的 Redis KEYS 命令:

警告:将 KEYS 视为仅应极其小心地在生产环境中使用的命令。当它针对大型数据库执行时,它可能会破坏性能。

Redis 文档建议使用 SCAN。

redis-cli --scan | while read LINE ; do TTL=`redis-cli ttl "$LINE"`; if [ $TTL -eq  -1 ]; then echo "$LINE"; fi; done;

如果要扫描特定键模式,请使用:

 redis-cli --scan --pattern "something*"

【讨论】:

    【解决方案2】:

    我需要从更大的 (40GB) 数据集中提取未过期的密钥,因此使用 keys 命令不适合我。因此,如果有人正在寻找离线/非阻塞解决方案,您可以使用https://github.com/sripathikrishnan/redis-rdb-tools 从 redis rdb 转储中提取非过期密钥。

    你可以通过 pip 安装库:

    pip install rdbtools python-lzf

    然后创建一个简单的解析器来提取过期设置为无的键和值:

    from rdbtools import RdbParser, RdbCallback
    from rdbtools.encodehelpers import bytes_to_unicode
    
    class ParserCallback(RdbCallback):
    
        def __init__(self):
            super(ParserCallback, self).__init__(string_escape=None)
    
        def encode_key(self, key):
            return bytes_to_unicode(key, self._escape, skip_printable=True)
    
        def encode_value(self, val):
            return bytes_to_unicode(val, self._escape)
    
        def set(self, key, value, expiry, info):
            if expiry is None:
                print('%s = %s' % (self.encode_key(key), self.encode_value(value)))
    
    
    callback = ParserCallback()
    parser = RdbParser(callback)
    parser.parse('/path/to/dump.rdb')
    

    【讨论】:

    • 不错!这绝对是 2021 年的最佳答案(假设您可以访问 RDB 文件,而托管服务并非如此)。
    • @aron23 输出中似乎没有打印集合,只有字符串类型的键
    【解决方案3】:

    从我现在找不到的网站修改。

    redis-cli keys  "*" | while read LINE ; do TTL=`redis-cli ttl "$LINE"`; if [ $TTL -eq  -1 ]; then echo "$LINE"; fi; done;
    

    编辑:注意,这是一个阻塞调用。

    【讨论】:

    • TTL 是 -1 没有过期密钥(而不是 3600)。
    • 这是一个很好的观点,感谢您指出。编辑了答案并支持您的评论。
    • 在远程 redis 主机上尝试此操作时出现错误。我连接到远程主机,然后从提示符运行:keys "*" | while read LINE ; do TTL=redis-cli ttl $LINE; if [ $TTL -eq -1 ]; then echo "$LINE"; fi; done; 但我收到“无效参数”错误
    • 请确保双引号$TTL。如果其中一个键有空格,bash 将给出bash: [: too many arguments 错误。此外,由于此错误,我不得不使用== 而不是-eqbash: [: ERR wrong number of arguments for 'ttl' command: integer expression expected
    • Redis KEYS command 可以阻止 Redis 处理请求。根据您的架构,使用 SCAN 将只占用大约 10% 的引擎 CPU。
    【解决方案4】:

    如果有人得到错误的参数或错误数量的参数错误, 在 $LINE 周围加上双引号。

    原来如此

    redis-cli keys  "*" | while read LINE ; do TTL=`redis-cli ttl "$LINE"`; if [ $TTL -eq  -1 ]; then echo "$LINE"; fi; done;
    

    当键中有空格时会发生这种情况。

    【讨论】:

    • 这是对现有答案的改进(错误修复),因此应该是对该答案的编辑。
    【解决方案5】:
    #!/usr/bin/env python
    
    import argparse
    import redis
    
    p = argparse.ArgumentParser()
    p.add_argument("-i", '--host', type=str, default="127.0.0.1", help="redis host", required=False)
    p.add_argument("-p", '--port', type=int, default=6379, help="redis port", required=False)
    p.add_argument("-n", '--db', type=int, default=0, help="redis database", required=False)
    
    args = p.parse_args()
    
    r = redis.Redis(host=args.host, port=args.port, db=args.db)
    
    try:
        keys = r.keys()
    
        for key in keys:
            if r.ttl(key) < 0:
                print(key)
    except KeyboardInterrupt:
        pass
    

    【讨论】:

      【解决方案6】:

      在我看来,接受的答案对于中型数据集似乎不可用,因为它会为每个键运行 redis-cli 命令。

      我使用这个 lua 脚本来过滤 redis 服务器中的键:

      local show_persistent = ARGV[1] ~= "expiring"
      
      local keys = {}
      for i, name in ipairs(redis.call("keys", "*")) do
          local persistent = redis.call("pttl", name) < 0
          if persistent == show_persistent then
              table.insert(keys, name)
          end
      end
      
      return keys
      

      这可以称为

      $ redis-cli --eval show-persistent-keys.lua
      

      获取所有没有过期时间的密钥。也可以称为

      $ redis-cli --eval show-persistent-keys.lua , expiring
      

      找到所有设置了过期时间的密钥的相反密钥集。

      不利的一面是,这可能会阻塞太久(对于 1 M 键来说似乎很好)。我会改用扫描,但我碰巧必须在 2.6 版的旧版 Redis 上运行它,它没有 scan 可用。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-01-20
        • 2015-08-16
        • 2013-05-20
        • 2013-05-08
        • 1970-01-01
        • 2020-04-03
        • 1970-01-01
        相关资源
        最近更新 更多