1. 程式人生 > >redis中KEYS和SCAN命令對比

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