keys
KEY*模糊查询导致交互速度慢、阻塞其他 Redis 操作
查询速度慢的原因
在Redis中,使用通配符 KEYS 命令进行键的模糊匹配(比如 KEYS key*)可能会导致性能问题,尤其是在数据集较大时。这是因为 KEYS 命令的实现需要遍历所有的键来匹配模式,这个过程的时间复杂度是 O(N),其中 N 是键的总数,因此使用KEYS*命令查询时,Redis的响应速度和Redis中数据量成正比。
在大规模的生产环境中,遍历所有键可能会导致阻塞其他 Redis 操作,因为 KEYS 命令会持有数据库的写锁。此外,这也可能对性能产生负面影响,因为它需要消耗大量的计算资源。在 Redis 中,所有命令都是按顺序执行的,一个命令执行完成后,才会执行下一个命令。这个单线程模型是 Redis 的设计选择之一,有助于简化并发控制,提高数据一致性。
使用带前缀的通配符 KEYS prefix*
在 Redis 中,使用带前缀的通配符 KEYS prefix* 仍然需要遍历所有匹配前缀的键。虽然带有前缀的通配符能够减小匹配的范围,但是在 Redis 中并没有内置的索引结构能够直接加速带有通配符的键的查找。
这是因为Redis 的键是以哈希表的形式存储的,通过哈希函数计算出键的位置。当使用通配符 KEYS prefix* 时,Redis 无法直接利用哈希函数来快速定位符合条件的键,而需要遍历哈希表中的所有键,然后筛选匹配的键。
如果对于特定的使用场景,你经常需要根据键的前缀来查询数据,可以考虑使用 Redis 的有序集合(Sorted Set)来模拟带有前缀的键的查询。在有序集合中,你可以将键的前缀作为分数,然后使用范围查询来获取符合条件的键。这样可以更有效地执行带有前缀的查询,但这需要根据具体情况来设计和维护有序集合。
总体来说,避免在生产环境中使用 KEYS 命令,尤其是在大规模数据集上,因为它可能导致性能问题。在生产环境中,当出现使用KEYS*的场景时,一定要谨慎,考虑如何改变reid key的数据结构来避免使用;如果非要遍历所有keys不可,更推荐使用迭代命令(如 SCAN)以及结合合适的数据结构来执行查询,它可以用于迭代集合中的元素而不会阻塞整个数据库,特别是在大型数据库中,因为它将迭代的工作分散到多个步骤,并允许客户端逐步处理结果。这样可以避免 KEYS 命令可能引起的性能问题。
scan
特殊场景SCAN 一个用于迭代集合元素的命令
SCAN 是 Redis 提供的一个用于迭代集合元素的命令。它可以用于逐步迭代集合中的元素,而不会一次性获取所有元素。这样可以减小对 Redis 服务器的负载,并且不会阻塞其他的 Redis 命令。
这样的迭代方式可以有效地处理大型数据集,减小对 Redis 服务器的压力。
Redis 的 SCAN
命令是一种非阻塞式的迭代键空间(key space)的方法,主要用于替代在大型数据库中一次性获取所有键的 KEYS
命令。KEYS
命令虽然能列出所有的键,但在大数据量下会阻塞 Redis 服务器直到命令执行完毕,这在生产环境中是不推荐使用的。
SCAN
命令的工作原理如下:
-
游标机制:
SCAN
命令接受一个游标(cursor)作为输入参数,并在执行后返回一个新的游标以及一批键(keys)。初始调用时,游标值应设为0
。后续调用时,使用上一次SCAN
返回的新游标作为下次调用的游标值。当返回的游标值为0
时,表示迭代完成。 -
渐进式遍历:
SCAN
不保证在单次调用中返回所有键,而是每次返回一部分键。这是因为它采用了渐进式遍历策略,只在当前迭代周期内扫描部分哈希槽或者字典的一部分。 -
可选参数:
MATCH pattern
:允许用户指定匹配模式,仅返回符合给定 Glob 风格模式的键。COUNT count
:设置期望每次迭代返回的元素数量上限。不过,这只是个提示值,实际返回的数量可能少于或多于count
指定的数量。
-
内部实现: Redis 内部维护着一个哈希表结构来存储键值对。
SCAN
命令通过游标机制实现了高效的遍历,即使在哈希表进行 rehash 或者数据库大小动态变化的情况下也能继续迭代而不会错过或重复键。 -
一致性问题: 因为
SCAN
命令是非阻塞并且实时的,所以在遍历过程中如果有其他客户端修改了数据库(比如新增、删除键),可能会造成遍历结果的一致性问题,即无法保证在遍历期间键集的不变性。
总结来说,SCAN
命令通过不断调用并在每次调用之间传递游标的方式来分批次地获取键空间中的键,适用于大规模数据的遍历场景,同时兼顾了性能和系统的响应能力。