当前位置:首页 > 问答 > 正文

Redis怎么针对某个IP来清缓存,操作步骤和注意点分享

Redis本身并没有一个内置的命令叫做“删除某个IP的缓存”,这是因为Redis是键值对数据库,它只认key(键),不关心这个key是谁存的或者这个key对应的值是什么内容(比如是否包含IP信息),我们的目标实际上变成了:如何找到并删除那些键名或键值中包含特定IP地址的所有key

要实现这个目标,整个操作可以分为三个核心步骤:制定键名规范、查找相关键、执行删除操作,下面详细说明。

操作步骤

第一步:制定键名规范(这是最重要的前提)

在你开始写代码缓存数据的时候,就要想好以后怎么清理,如果你的key命名是乱七八糟的,比如随便用 user123, product456, session_abc 这种,那么想通过IP来清理缓存几乎是不可能的。

正确的做法是,在key中融入IP地址信息。 这里提供几种常见的思路,你可以根据业务场景选择:

  1. 前缀法(最常用):将IP作为key的前缀。

    • 格式IP:业务标识:唯一ID
    • 例子:假设IP是 168.1.100,要缓存用户数据,key可以设计为 168.1.100:user:profile:123,这样,所有这个IP产生的用户资料缓存都有一个共同的前缀 168.1.100:user:
  2. 后缀法:将IP作为key的后缀(较少用,但某些场景适用)。

    • 格式业务标识:唯一ID:IP
    • 例子page:index:html:192.168.1.100
  3. Hash结构法:如果一个IP对应多条缓存数据,可以考虑使用Redis的Hash数据类型。

    • 格式:用一个大的key来存储,ip:192.168.1.100:cached_data,然后在这个Hash里面,用字段(field)来区分不同的数据。
    • 例子HSET ip:192.168.1.100:cached_data user_profile '{"name": "张三"}' page_settings '{"theme": "dark"}'
    • 这样,要清空这个IP的所有缓存,直接删除这个大的key就行了。

假设我们采用最常用的“前缀法”,接下来的步骤就基于这个前提。

第二步:查找匹配的键

找到了包含IP的key,我们使用Redis的 SCAN 命令来查找,绝对不要使用 KEYS 命令,原因在注意事项里会详细说。

操作命令示例: 假设我们要找IP为 168.1.100 的所有key,我们设计的前缀是 168.1.100:

在Redis命令行中,你可以这样逐步扫描:

# 第一次扫描,cursor从0开始,匹配模式是 192.168.1.100:*
127.0.0.1:6379> SCAN 0 MATCH 192.168.1.100:* COUNT 100
1) "53" # 下一次扫描的游标,如果为0表示扫描完毕
2) 1) "192.168.1.100:user:profile:123"
   2) "192.168.1.100:product:list:456"
# 使用上面返回的新游标“53”继续扫描
127.0.0.1:6379> SCAN 53 MATCH 192.168.1.100:* COUNT 100
1) "0" # 游标为0,表示所有匹配的key都找到了
2) (empty list or set)

在实际应用中,你需要写一个循环脚本来完成整个SCAN过程,直到游标返回0为止。

第三步:执行删除操作

找到所有匹配的key之后,就可以删除了,删除有两种方式:

  1. 使用 DEL 命令:这是最直接的方法。

    • 如果你在命令行手动操作,可以把第二步中找到的所有key一个个用 DEL 命令删除。
    • 如果在程序中,你可以将SCAN找到的key列表直接传给 DEL 命令(大多数Redis客户端支持批量删除)。
    • 命令示例DEL key1 key2 key3 ...
  2. 使用Lua脚本:这是更推荐在生产环境使用的方法,因为它能保证原子性,避免了在扫描和删除之间,又有新的key被创建而无法删除的问题。

    • 一个简单的Lua脚本示例:
      local keys = redis.call('KEYS', ARGV[1])
      for i=1, #keys, 1 do
          redis.call('DEL', keys[i])
      end
      return #keys
    • 注意:这个脚本内部使用了 KEYS 命令,只能在你非常确定匹配的key数量很少,且Redis正在空闲时使用,否则会阻塞服务器,更安全的Lua脚本需要自己用 SCAN 实现,但比较复杂,通常批量 DEL 足矣。

关键注意点分享

  1. 绝对禁止在生产环境使用 KEYS 命令:这是最重要的注意事项。KEYS 命令会一次性遍历数据库中的所有key,如果key的数量巨大(几百万甚至更多),会导致Redis服务卡住数秒甚至更久,所有后续请求都会被阻塞,可能引起服务雪崩。SCAN 命令是增量式的,不会阻塞服务器。

  2. 规划优于补救:再次强调,能否顺利按IP清理缓存,完全取决于最初设计key结构时的规划,如果项目已经上线,key结构混乱,retroactive(追溯)地清理某个IP的缓存会非常困难,可能需要遍历所有key并检查其值,成本极高。

  3. 考虑使用通配符的灵活性:在扫描时,你的匹配模式可以更灵活,如果你只想删除某个IP下与用户(user)相关的缓存,模式可以写为 168.1.100:user:*,如果你要删除该IP的所有缓存,则用 168.1.100:*

  4. 确认再删除:在执行批量删除操作前,特别是在生产环境,务必先通过 SCAN 命令预览一下会被删除的key列表,确认无误后再执行 DEL,误删大量缓存可能会导致数据库压力瞬间增大,击穿缓存。

  5. 考虑设置TTL(过期时间):作为一种容错和资源清理机制,在设置缓存时,就应该给key加上一个合理的过期时间(TTL),这样即使清理脚本因为某种原因没有执行,这些key也会在过期后自动被Redis删除,避免无用数据长期堆积。

  6. 权限控制:执行删除操作的Redis账号需要有相应的权限,在生产环境中,应该使用一个权限受限的账号,只授予它必要的命令执行权限(如 SCAN, DEL),而不是使用最高权限的账号,以提高安全性。

通过IP清理Redis缓存的核心在于“如何标记key”,这是一个需要在项目初期就做的设计决策,操作本身通过 SCANDEL 的组合可以安全有效地完成,但务必牢记相关注意事项,尤其是在生产环境中的风险。

Redis怎么针对某个IP来清缓存,操作步骤和注意点分享