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

Redis模糊查找其实没那么难,教你几招提升效率别再慢吞吞

开始)

你是不是也遇到过这种情况?想在Redis里找那些键名记不全的键,比如所有以“user:session:”开头的会话,或者包含“cache_2024”的临时数据?然后你兴冲冲地用了KEYS这个命令,结果发现当数据库里key数量一多,整个Redis服务器竟然卡住了,请求超时,其他业务也跟着遭殃,这时候你可能觉得Redis的模糊查找真是个坑,太难用了。

其实啊,这不是Redis的错,而是我们用错了方法,网上很多简单的教程一上来就教KEYS pattern,但却没告诉你背后的陷阱,今天我们就来聊聊,怎么才能既实现模糊查找,又不让服务器“罢工”,让你彻底告别慢吞吞的查询。

第一招:认清“杀手”KEYS,请用SCAN替代

首先要明白一个关键点,为什么KEYS命令这么危险,根据来自Redis官方文档的说明,KEYS命令在执行时会遍历数据库里的所有key,然后一次性把所有匹配的结果都返回给你,这个过程是同步的,也就是说,在它吭哧吭哧遍历的时候,Redis主线程就被它独占了,其他所有命令都得排队等着,如果你的Redis存了几百万甚至上千万个key,这个遍历过程可能会长达好几秒甚至更久,这对于一个高性能的内存数据库来说简直是灾难。

那该怎么办呢?Redis提供了一个救星命令:SCAN,根据Redis官方文档解释,SCAN命令的核心原理是迭代式遍历,它不会一次性扫完全库,而是每次只扫描一小部分,然后返回一个游标(cursor)和一部分匹配的key,你可以拿着这个游标,再次调用SCAN,继续从上一次的位置开始扫描,虽然整个过程最终也会扫描全库,但它是分多次、非阻塞地完成的,每次只占用一点点CPU时间,不会影响其他请求的正常处理。

使用起来是这样的:

SCAN 0 MATCH user:session:* COUNT 100

这里的0表示从第一次扫描开始,MATCH后面跟你的模糊模式(和KEYS的语法一样),COUNT是建议每次扫描的数量(注意只是个建议值,Redis不一定完全遵守),执行后,Redis会返回一个新的游标值(比如12345)和一批key,如果新的游标值是0,说明遍历结束了;如果不是0,你就需要用这个新游标继续查,直到游标变回0

第二招:从设计上根治问题——别让key“无处可寻”

就算用了SCAN,如果需要在海量key中做模糊匹配,毕竟还是一种“事后补救”的措施,效率上限摆在那里,最高级的优化,其实是在设计key的时候,就为查找铺好路,这就是所谓的“治本之策”。

一个非常推荐的实践是,使用合适的数据结构来管理一组相关的key,文章开头的例子,我们要找所有user:session:123, user:session:456这样的key,与其用SCAN去模糊匹配user:session:*,不如用一个Redis的集合(Set)或有序集合(Sorted Set)。

具体怎么做呢?你可以在每次创建一个用户会话key时,同时执行两条命令:

SET user:session:123 "session_data_here"
SADD user:sessions 123

第一条命令是正常的存储会话数据,第二条命令,是把这个会话的用户ID 123,添加到一个名为user:sessions的集合中。

这样一来,当你想获取所有活跃会话对应的用户ID时,根本不需要模糊查找,直接一条命令搞定:

SMEMBERS user:sessions

然后你再根据返回的用户ID列表,去精准地获取每一个user:session:[id]的数据,这种方法的时间复杂度是O(1)(SADD)和O(N)(SMEMBERS加上N次GET),远比在海量key中做模式匹配要高效和可控得多,对于需要按时间顺序排列的场景,可以用有序集合(ZSET),把创建时间作为分数(score)存进去,查询起来就更强大了。

第三招:理解模式匹配的写法,避免踩坑

虽然我们尽量避免模糊查询,但有时候还是免不了要用到SCANKEYS(仅限测试环境!)的模式匹配,这里有几个小技巧让你更高效。

模式匹配主要支持三种通配符:

  • :匹配任意数量的任意字符(包括零个)。
  • :匹配一个任意字符。
  • [abc]:匹配括号内的某一个字符。

根据多位Redis用户在社区(如Stack Overflow)的实践经验,有一个重要的提示:尽量让模式的前缀是明确的user:session:*这个模式就很好,因为Redis从第一个字符开始匹配,遇到明确的字符串user:session:后,可以快速跳过大量不相关的key,而如果你用*session*这种模式,因为它要从所有key的每一个位置去匹配“session”这个词,效率就会低很多,这就好比在一本字典里,找所有以“阿”开头的字很容易,但找所有包含“阿”字的字就得一页一页翻,是一个道理。

总结一下

别再抱怨Redis模糊查找慢了,提升效率的关键就三点:

  1. 弃用KEYS,拥抱SCAN:这是保证生产环境稳定性的底线。
  2. 优化Key设计,用集合管理:这是从根源上减少甚至消除模糊查询的需求,是最高效的方式。
  3. 明确匹配模式的前缀:如果非得用模糊匹配,尽量让模式开头有确定的字符串。

Redis是单线程的,任何可能耗时的操作都需要我们格外小心,掌握了这几招,你就能在需要灵活查询的同时,依然让Redis保持风驰电掣的速度。 结束)

Redis模糊查找其实没那么难,教你几招提升效率别再慢吞吞