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

怎么用Redis快速拿到所有键值对,redis里获取全量keys的方法分享

主要参考了Redis官方文档、多个技术社区如Stack Overflow的常见问答以及《Redis设计与实现》一书中的相关章节)

需要明确一个核心点:在Redis里,没有一个单一的命令可以直接一次性返回所有键(key)和它们对应的值(value),你需要分两步走:第一步是获取所有的键,第二步是根据这些键去逐个或批量地获取值,问题的关键在于如何高效、安全地完成第一步——获取所有键。

使用 KEYS 命令(最简单,但最危险)

这可能是很多人第一个想到的方法,命令格式非常简单:

KEYS *

这个命令会匹配并返回Redis数据库中所有的键,如果你只想找特定模式的键,比如以"user:"开头的,可以用 KEYS user:*

  • 优点:简单直接,一句话搞定。
  • 致命缺点绝对不推荐在生产环境中使用! 因为KEYS命令会一次性遍历整个数据库的所有键,如果你的Redis里存了几百万甚至上亿个键,这个命令会长时间阻塞Redis的单线程,导致在这段时间内Redis无法处理任何其他的读写请求,整个服务就像卡死了一样,很可能引发线上服务瘫痪,书里和官方文档都强烈警告了这一点。

KEYS命令只适合你在本地开发环境,或者确定数据库里键的数量非常少(比如几百个)的情况下,临时调试用一下。

使用 SCAN 命令(推荐的生产环境方法)

为了解决KEYS命令的阻塞问题,Redis从2.8版本开始引入了SCAN命令,SCAN命令是一种迭代器方式的扫描,它不会一次性遍历所有键,而是分多次进行,每次只返回一小部分键和一个游标(cursor),你拿到游标后,下次请求带着这个游标,它就会从上次停下的地方继续扫描。

基本用法是这样的:

怎么用Redis快速拿到所有键值对,redis里获取全量keys的方法分享

SCAN 0

这里的0表示从游标0开始第一次扫描,命令返回的结果是两个:第一个是下一次扫描需要用的新游标,第二个是本次扫描到的键的列表,当返回的新游标是0时,表示整个遍历已经完成。

  • 优点
    1. 非阻塞:由于每次只扫描一小部分,所以对Redis服务器的性能影响非常小,可以安全地在生产环境使用。
    2. 可控:你可以控制每次迭代的步长(通过COUNT参数,比如SCAN 0 COUNT 100),虽然COUNT只是一个参考值,Redis不保证每次返回 exactly 那个数量,但大体上能控制节奏。
  • 需要注意:SCAN命令在遍历过程中,如果数据库的键有增加、删除或修改,可能会遇到重复键或者某次遍历不到的轻微问题(因为是基于游标的快照),但对于全量获取这种场景,最终能保证所有键都会被遍历到。

获取到键列表后,如何高效地拿到所有值?

现在你有了所有键的列表(无论是用危险的方法一还是安全的方法二得到的),下一步就是取回值,如果你有几千个键,用GET key1GET key2...这样一条条发命令,网络往返开销会非常大,效率极低。

这里就要用到批量操作命令了:

  1. 使用 PIPELINE(管道): 管道技术允许你一次性发送多个GET命令到服务器,而不用等待每个命令的响应,最后再一次性读取所有的回复,这极大地减少了网络延迟带来的开销,几乎所有Redis客户端都支持管道操作,你可以把从SCAN命令得到的键列表,分批(比如每100个一批)通过管道发送GET请求。

    怎么用Redis快速拿到所有键值对,redis里获取全量keys的方法分享

  2. 使用 MGET 命令: 如果你要获取的键对应的值都是同一种类型(比如都是字符串String),那么可以直接使用MGET key1 key2 key3 ...命令,它能在一条命令里获取多个键的值,这比管道更方便,但要注意,MGET命令一次性能处理的键数量不是无限的,如果键数量巨大,你可能还是需要分成多个MGET批次来处理,或者结合管道发送多个MGET。

一个安全高效的组合拳流程是:

  1. 使用 SCAN 命令迭代地、非阻塞地获取数据库中所有的键,存入一个本地列表。
  2. 将这个巨大的键列表,在本地分成一个个小批次(比如每100个或200个一批)。
  3. 对于每一批键,使用 PIPELINE 发送多个 GET 命令(或者如果值类型一致且批量不大,直接用 MGET)。
  4. 处理每一批返回的结果值。

特殊情况:如果值不是字符串怎么办?

上面的GET和MGET只适用于字符串类型的值,如果你的Redis里还存了哈希(Hash)、列表(List)、集合(Set)等复杂类型,你需要使用对应的命令来获取全量数据:

  • 对于哈希(Hash):用 HGETALL key 命令来获取单个键的所有字段和值,同样,可以结合SCAN和管道批量处理。
  • 对于列表(List):用 LRANGE key 0 -1 来获取列表的全部元素。
  • 其他类型以此类推。

总结一下核心思想:

想快速从Redis拿全量键值对,关键在于“分而治之”,不要试图用一条命令完成所有工作,正确的做法是:

  • 扫描键:用安全的 SCAN 替代危险的 KEYS,分批遍历。
  • 获取值:用 PIPELINE(管道)或 MGET 等批量操作,减少网络通信次数。

严格按照这个思路来,即使面对海量数据,也能在保证Redis服务稳定的前提下,相对快速地完成全量数据的获取。