redis中KEYS和SCAN命令对比

redis中KEYS和SCAN命令对比

根据官方文档所述,KEYS命令时间复杂度是O(N),耗费时间很少,在笔记本上扫描100w个key的数据库使用了40ms。不推荐在实际生产环境使用KEYS命令,在数据量比较大的情况下执行该命令会有很大的性能损耗,这个命令是用来调试和其他特殊用途,比如,改变key空间的布局。在正式应用代码里使用SCAN和sets代替KEYS。

KEYS就是将redis中所有的key与KEYS参数一一匹配,但是这个匹配过程对服务器性能有很大的损耗。而SCAN则是将所有key分页处理,每次处理的条数通过参数传入。处理后返回一个游标,下次再次请求的时候携带该游标。
下面对KEYS和SCAN的性能和使用方式进行对比。
测试环境:
server:redis_version:5.0.2 运行在docker容器里,宿主机配置 i7-6700K,IP为192.168.1.160。image: redis:alpine, cpu默认配置可以占满一个核,映射出来的端口为6380。
client: ubuntu16.04 编程语言为node.js v10.15.0,依赖库 redis: 2.8.0,uuid: 3.3.2。

首先我先在redis中插入100w条数据。代码如下:

const { v4 } = require('uuid');
const { createClient } = require('redis');
const client = createClient({
    host: '192.168.1.160',
    port: 6380,
});


const set = (key) => {
    return new Promise((resolve, reject) => {
        client.set(key, key, (err, reply) => {
            if (err)
                reject(err);
            return resolve();
        });
    });
};
let uuidList = [];

const run = async () => {
    const start = new Date().getTime();
    for (let i = 0; i < 100; i++) {
        for (let i = 0; i < 10000; i++) {
            uuidList.push(v4());
        }
        await Promise.all(uuidList.map(uuid => {
            return set(uuid);
        }));
        uuidList = [];
    }
    console.log('duration', new Date().getTime() - start);
};
run();

接下来测试KEYS查询,代码如下:

const { createClient } = require('redis');
const client = createClient({
    host: '192.168.1.160',
    port: 6380,
});


const start = new Date().getTime();
client.keys('*ccccc*', (err, reply) => {
    const duration = new Date().getTime() - start;
    console.log('duration');
    console.log(reply.sort());
});

搜索到的结果为:

[ '2aaf224c-a31f-4555-8269-ccccc4b68244',
  '317c73a2-40ef-4084-a7fa-8c2ccccc8817',
  '3ccccc6b-bd15-4cc1-b857-2eb2ee35c147',
  '8b4ce8df-17d5-40f5-a44a-86971f9ccccc',
  'a8de5fe2-181a-4628-80dc-eccccc613f9f',
  'a981dea3-1d9b-4038-a2f6-7ccccc9e88e1',
  'd8ccccc5-3c5b-4bf8-b73b-c6c45c8ce41f',
  'f137ad17-5b21-43d1-a77c-2eae5cccccdd' ]

平均耗时为:310ms。
接下来测试SCAN查询,代码如下:

const { createClient } = require('redis');
const client = createClient({
    host: '192.168.1.160',
    port: 6380,
});

const scan = (cursor, keys, count) => {
    return new Promise((reslove, reject) => {
        client.scan(cursor, 'MATCH', keys, 'COUNT', count, (err, res) => {
            if (err) {
                reject(err);
            }
            const [cursor, matched] = res;
            return reslove({ cursor, matched });
        });
    });
};

const run = async () => {
    const result = [];
    const start = new Date().getTime();
    let cursor = 0;
    const keys = '*ccccc*';
    while (true) {
        const { matched, cursor: newCursor } = await scan(cursor, keys, process.argv[2]);
        result.push(...matched);
        cursor = newCursor;
        if (cursor === '0') {
            console.log('duration', new Date().getTime() - start);
            break;
        }
    }
    console.log(result.sort());
};

run();

COUNT分页大小与平均耗时:

大小 耗时
1k 2790ms
1w 664ms

猜你喜欢

转载自blog.csdn.net/u010293286/article/details/85843234