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

redis里哈希表太多了,一键快速清空怎么搞才方便又省事

当你面对Redis里堆积如山的哈希表,想要快速清理时,最直接的想法可能就是找个办法一口气全干掉,这事儿说简单也简单,说麻烦也麻烦,关键看你怎么操作,最省事的方法,绝对不是一个个手动去删,那得删到猴年马月,下面这几种路子,你可以根据实际情况选最顺手的。

最暴力但也最彻底的一招:直接重启并清空整个Redis

这招是核武器,效果立竿见影,如果你确认这个Redis实例里的所有数据,注意是所有数据,都可以不要了,那么这就是最快、最省心的办法。

具体操作就是找到Redis的配置文件,通常叫 redis.conf,里面有两个关键配置项,决定了Redis启动时如何加载数据:

  1. dbfilename:这个指定了持久化数据文件的名字,默认是 dump.rdb
  2. dir:这个指定了数据文件存放的目录,默认是Redis的安装根目录。

你的操作步骤是这样的:

  • 务必确保你已经和团队或其他使用者沟通好,确认清空整个数据库没有影响,这一步千万不能省,不然可能酿成大祸。
  • 停止Redis服务,在Linux上,命令通常是 sudo systemctl stop redis 或者 redis-cli shutdown
  • 找到 dir 目录下的 dbfilename 文件(dump.rdb),直接把它删除,如果还开启了AOF持久化(会有 appendonly.aof 文件),最好也一并删掉,以绝后患。
  • 重新启动Redis服务,sudo systemctl start redis

Redis启动时发现既没有RDB文件也没有AOF文件,它就会创建一个全新的、空空如也的数据库,这样一来,别说哈希表了,所有类型的数据都没了,世界瞬间清净,这种方法最适合测试环境重置、或者整个业务模块下线需要清理数据的场景。(此方法为Redis标准数据持久化机制的应用,常见于官方文档和运维手册)

精准打击的常规武器:使用 FLUSHALLFLUSHDB 命令

如果你不想重启服务,或者只想清空当前选中的那个数据库,而不是整个Redis实例,那么Redis内置的命令就是你的首选。

  • FLUSHALL:这个命令会清空Redis服务器上所有数据库里的所有数据,Redis默认有16个数据库(编号0-15),这个命令一扫光,威力巨大,在 redis-cli 里直接输入 FLUSHALL 回车,数据就没了。
  • FLUSHDB:这个命令只会清空你当前连接的那个数据库里的所有数据,比如你现在在用第0号数据库,FLUSHDB 就只清空0号库,其他1到15号库不受影响。

这两个命令执行速度都非常快,因为Redis在内部是直接释放内存,几乎瞬间完成,它们有一个潜在的“副作用”:如果你的Redis数据量特别大(比如几十个GB),执行这两个命令可能会导致Redis进程短暂地“卡顿”一下,这是因为释放大量内存后,操作系统需要时间来回收和整理内存页,这个过程可能会阻塞其他请求。

为了解决这个卡顿问题,Redis从4.0版本开始,给这两个命令加了一个超好用的选项:ASYNC

  • 你可以这样用:FLUSHALL ASYNC 或者 FLUSHDB ASYNC
  • 加上 ASYNC 之后,Redis会另启一个后台线程去慢慢清理内存,而主线程会立刻返回OK,继续处理客户端的其他请求,这样就避免了服务阻塞。(Redis 4.0引入FLUSHALL/FLUSHDB ASYNC特性,旨在解决大内存实例清空时的延迟问题,该信息可在Redis版本发布说明中找到)

对于你的“哈希表太多”的问题,如果这些哈希表都在同一个数据库里,用 FLUSHDB ASYNC 是最佳选择,既快又不影响服务,如果它们分散在不同的数据库,那就只能用 FLUSHALL ASYNC 了。

需要写点脚本的“外科手术”:用Lua脚本批量扫描删除

情况会更复杂一些,你只想删除某一部分有共同特征的哈希表,而不是整个数据库,比如说,所有以 "user_session:" 开头的哈希表要清理,但其他数据得保留,这时候,上面两种“地图炮”方法就不行了,需要更精准的“外科手术”。

Redis没有提供按模式批量删除键的直接命令,但我们可以组合使用 SCAN 命令和 DEL 命令来实现,而最高效的方式,就是写一个Lua脚本,在服务器端原子性地执行。

假设你要删除所有以 "cache:" 开头的键(不管它是哈希表、字符串还是别的类型),一个简单的Lua脚本如下:

local cursor = 0
local pattern = ARGV[1] -- 从参数获取匹配模式,"cache:*"
local count = 100 -- 每次扫描的数量
repeat
    local result = redis.call('SCAN', cursor, 'MATCH', pattern, 'COUNT', count)
    cursor = tonumber(result[1])
    local keys = result[2]
    for i, key in ipairs(keys) do
        redis.call('DEL', key)
    end
    if cursor == 0 then
        break
    end
until false
return "OK"

直接在 redis-cli 里写这么长一段循环不太方便,更实用的方法是把脚本写在一个文件里(比如叫 delete_by_pattern.lua),然后用 redis-cli 来执行:

redis-cli --eval delete_by_pattern.lua , "cache:*"

为什么用Lua脚本? 因为Lua脚本在Redis中是原子执行的,在执行脚本期间,不会有其他命令插队,保证了删除操作的一致性,脚本在网络上是“一次传输,一次执行”,比你在客户端一条条发 SCANDEL 命令要快得多,网络开销小。(使用SCAN+Lua脚本进行模式化批量删除是Redis社区公认的最佳实践,在Stack Overflow等开发者社区有大量讨论)

怎么选最省事:

  • 整个Redis实例的数据都不要了。
    • 方法: 停服务、删RDB/AOF文件、再重启,这是最彻底的“省事”。
  • 清空当前数据库或所有数据库,不区分键的类型。
    • 方法: 直接使用 FLUSHDB ASYNCFLUSHALL ASYNC,这是最快速的“省事”。
  • 只清空特定模式的键(比如一批哈希表),其他数据要保留。
    • 方法: 编写并执行Lua脚本进行模式匹配删除,这是最精准的“省事”。

最后再啰嗦一句,无论用哪种方法,尤其是在生产环境,动手前一定要备份数据或者再三确认!你可以先用 INFO keyspace 命令看看大概的键数量,或者用 SCAN 命令模拟一下要删除的键是不是你预期的那些,清空操作一旦执行,可没有回收站给你找回来。

redis里哈希表太多了,一键快速清空怎么搞才方便又省事