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

Redis里怎么快速优雅地一键清理指定数据,真没那么复杂

(引用来源:Redis 官方文档、常见运维实践)

说到清理Redis里的特定数据,很多人可能觉得是个技术活儿,得写复杂脚本或者用一堆看不懂的命令,其实真没那么复杂,核心思路就两个:要么用对命令,要么提前规划好,只要掌握了要领,一键清理可以很轻松。

核心武器:DEL 和 UNLINK

清理数据,最直接的想法就是删除,Redis提供了两个关键命令:DELUNLINK

  1. DEL 命令:这是最基础的删除命令,比如你想删除一个叫 user:1001:cart 的键,直接执行 DEL user:1001:cart 就行了,它简单粗暴,同步执行,意思是服务器会立刻把这个键删掉,然后才返回结果给你,如果你要删的键不多、不大,用 DEL 没问题。

  2. UNLINK 命令:这是Redis 4.0版本之后提供的“优雅”版删除命令,用法和 DEL 一模一样,UNLINK user:1001:cart,那它优雅在哪呢?它是“异步”的,当你执行 UNLINK 时,Redis会先把键从键空间里“摘”出来,让你以后再也访问不到它了,然后立刻返回成功给你,至于真正释放内存这个比较耗时的苦力活,Redis会放到后台线程里慢慢去干,这样就不会因为删除一个特别大的键(比如一个包含几百万元素的Hash键)而阻塞服务器,导致其他请求卡住。在现代版本的Redis中,UNLINK 通常是比 DEL 更推荐的选择,尤其是在生产环境。

    Redis里怎么快速优雅地一键清理指定数据,真没那么复杂

一键清理的关键:模式匹配

光会删一个键不够,我们要的是“一键清理”一批键,这就要用到Redis的 KEYS 命令。KEYS 命令允许你使用通配符来查找所有匹配的键。

  • KEYS user:*:匹配所有以 user: 开头的键。
  • KEYS session:abc*:匹配所有以 session:abc 开头的键。
  • KEYS *:temp:匹配所有以 :temp 结尾的键。

重要警告KEYS 命令虽然强大,但它有一个致命的缺点:它会阻塞Redis服务,Redis是单线程的,如果你的数据库里有几百万甚至上千万个键,执行一个 KEYS * 这样的模糊查询,会导致Redis在这段时间内无法处理任何其他请求,基本等于一次小型故障。绝对不可以在生产环境直接使用 KEYS 命令

真正的“快速优雅”组合拳:SCAN + UNLINK

既然 KEYS 不能用,那我们用什么来安全地找到所有想删的键呢?答案是 SCAN 命令。

Redis里怎么快速优雅地一键清理指定数据,真没那么复杂

SCAN 命令也是用来迭代数据库中的键的,但它是“非阻塞”的,它通过游标分批次地返回匹配的键,每次只返回一小部分,这样在遍历一个巨大数据库时,就不会对服务器性能造成明显影响。

一键清理指定模式数据的标准做法就是:

  1. 先用 SCAN 命令(结合模式匹配)在脚本里循环找出所有需要删除的键。
  2. 然后对找出来的每一个键,使用 UNLINK 命令进行异步删除。

你可以写一个简单的Shell脚本或者Python脚本来完成这个工作,下面是一个非常经典的Shell脚本示例,你可以根据实际情况修改:

#!/bin/bash
# 定义Redis的连接信息(如果不需要认证,可以去掉 -a 参数)
REDIS_HOST="127.0.0.1"
REDIS_PORT="6379"
REDIS_PASS="your_password" # 如果没有密码,将这行注释掉,并在下面的命令中去掉 -a $REDIS_PASS
# 定义要匹配的键的模式
PATTERN="your_prefix:*" # "cache:temp:*" 或 "user:12345:*"
# 使用 redis-cli 执行 SCAN 和 UNLINK
# 注意:这里使用了 `xargs` 来将 SCAN 找到的键一次性传递给 UNLINK
if [ -z "$REDIS_PASS" ]; then
    redis-cli -h $REDIS_HOST -p $REDIS_PORT --scan --pattern "$PATTERN" | xargs -L 1000 redis-cli -h $REDIS_HOST -p $REDIS_PORT unlink
else
    redis-cli -h $REDIS_HOST -p $REDIS_PORT -a $REDIS_PASS --no-auth-warning --scan --pattern "$PATTERN" | xargs -L 1000 redis-cli -h $REDIS_HOST -p $REDIS_PORT -a $REDIS_PASS --no-auth-warning unlink
fi
echo "清理完成!"

这个脚本的精髓在于:

  • redis-cli --scan --pattern "$PATTERN":这部分安全地(非阻塞)扫描出所有匹配的键。
  • | xargs -L 1000 redis-cli ... unlink:这部分将扫描到的键,每1000个作为一批,传递给 UNLINK 命令进行删除,分批是为了防止一次传递的参数过多。
  • 整个流程是流水线式的,高效且对服务影响极小。

更优雅的方式:从源头设计

Redis里怎么快速优雅地一键清理指定数据,真没那么复杂

除了事后清理,最高级的“优雅”其实是在设计数据时就想好怎么清理。

  1. 使用过期时间(TTL):如果你的数据本身就有生命周期(比如用户会话session、临时缓存),在存入Redis时就直接给它设置一个过期时间(使用 SETEX 命令或 EXPIRE 命令),时间一到,Redis会自动删除它,完全不用你操心,这是最推荐的做法。

  2. 使用有规律的键名:就像上面的例子,把同一类数据用统一的前缀命名,user:1001:profile, user:1001:orders,这样在需要清理某个用户的所有数据时,就可以用 SCANUNLINK 轻松搞定。

总结一下

快速优雅的一键清理,真没那么复杂:

  • 核心命令:放弃阻塞的 DELKEYS,拥抱非阻塞的 UNLINKSCAN
  • 实战工具:写一个简单的脚本,用 SCAN 找键,用 UNLINK 删键。
  • 终极优雅:给数据设置过期时间,并规划好清晰的键命名规则,让清理工作变得简单甚至无需手动干预。

记住这个组合,下次需要清理Redis数据时,你就不会再觉得头疼了。