Redis使用Scan而不是Keys
当需要模糊查询redis数据库中某一个key的时候,可以使用两种方式keys和scan。推荐使用scan。
以在 Node.js 中使用 ioredis 操作 Redis 的 KEYS 和 SCAN 为例:
前提条件
确保你已经安装了 ioredis 包。如果尚未安装,可以使用以下命令进行安装:
npm install ioredis基本设置
首先,导入 ioredis 并创建一个 Redis 客户端实例:
const Redis = require('ioredis');
// 创建 Redis 客户端
const redis = new Redis({
host: 'localhost', // Redis 服务器地址
port: 6379, // Redis 服务器端口
// password: 'your_password', // 如果 Redis 设置了密码,取消注释并设置
});使用 KEYS 命令
适用场景
简单查询,适用于开发和调试环境。
当 Redis 数据库中的键数量较少时。
使用方法
async function getKeysUsingKeys(pattern) {
try {
// 执行 KEYS 命令
const keys = await redis.keys(pattern);
console.log('Matching keys:', keys);
return keys;
} catch (error) {
console.error('Error fetching keys with KEYS:', error);
}
}
// 示例用法
const token = '12345';
const pattern = `*token:${token}`;
getKeysUsingKeys(pattern);解释
redis.keys(pattern):异步执行KEYS命令,返回所有匹配指定模式的键。模式构建:例如,
*token:12345匹配任何以token:12345结尾的键,比如user:abc:token:12345。
示例输出
Matching keys: [ 'user:abc:token:12345', 'admin:token:12345' ]注意事项
性能问题:
KEYS命令在 Redis 中具有线性时间复杂度(O(N)),当键的数量庞大时,会导致显著的性能下降。阻塞性:在执行期间,Redis 服务器可能会阻塞,影响其他客户端的请求。
使用 SCAN 命令
适用场景
生产环境中,键数量较大时。
需要非阻塞地迭代键。
使用方法
基本 SCAN 使用
async function getKeysUsingScan(pattern) {
let cursor = '0';
const matchingKeys = [];
do {
// 执行 SCAN 命令
const result = await redis.scan(cursor, 'MATCH', pattern, 'COUNT', 100);
cursor = result[0];
const keys = result[1];
matchingKeys.push(...keys);
} while (cursor !== '0');
console.log('Matching keys:', matchingKeys);
return matchingKeys;
}
// 示例用法
const token = '12345';
const pattern = `*token:${token}`;
getKeysUsingScan(pattern);使用 ioredis 的 Stream API
ioredis 提供了更高级的迭代方法,通过 Stream API 可以更方便地处理大量键。
const { Readable } = require('stream');
async function getKeysUsingScanStream(pattern) {
const stream = redis.scanStream({
match: pattern,
count: 100, // 每次扫描的数量,可以根据需要调整
});
const matchingKeys = [];
stream.on('data', (keys) => {
for (const key of keys) {
matchingKeys.push(key);
}
});
// 返回一个 Promise 来等待流的结束
await new Promise((resolve, reject) => {
stream.on('end', resolve);
stream.on('error', reject);
});
console.log('Matching keys:', matchingKeys);
return matchingKeys;
}
// 示例用法
const token = '12345';
const pattern = `*token:${token}`;
getKeysUsingScanStream(pattern);解释
redis.scan(cursor, 'MATCH', pattern, 'COUNT', 100):cursor:扫描的起始位置,首次调用时为'0'。'MATCH', pattern:指定匹配模式。'COUNT', 100:每次扫描返回的键数,实际返回的数量可能稍有不同。
scanStream:ioredis提供的流接口,自动处理游标迭代,简化扫描过程。适合处理大量键时使用,避免一次性内存占用过高。
优点
非阻塞:
SCAN命令不会阻塞 Redis 服务器,适合生产环境。渐进式扫描:可以分批处理键,降低内存和 CPU 的压力。
示例输出
Matching keys: [ 'user:abc:token:12345', 'admin:token:12345' ]注意事项
不保证顺序:
SCAN命令返回的键顺序不固定。可能重复或遗漏:在并发修改 Redis 数据库时,
SCAN可能会返回重复或遗漏的键。需要在应用逻辑中处理这些情况。
总结
KEYS命令:优点:简单易用,适合开发和调试。
缺点:在键数量庞大时性能差,可能阻塞 Redis 服务器。
SCAN命令:优点:非阻塞,适合生产环境,支持大规模键的迭代。
缺点:需要多次调用,复杂度稍高,可能有重复或遗漏。
ioredis的scanStreamAPI:优点:简化
SCAN迭代过程,适合处理大量键。缺点:需要理解流的操作方式。