Node-redis: Maneira eficiente de excluir chaves por padrão

Criado em 5 mar. 2018  ·  12Comentários  ·  Fonte: NodeRedis/node-redis

Estou trabalhando em um grande projeto e, em alguns lugares, tenho que deletar as chaves por um padrão, por exemplo, quero deletar todas as chaves que começam com filterProducts

Fiz uma pesquisa no Google e encontrei alguns métodos para fazer isso, como, por exemplo, o método deste artigo

Mas não sei qual é o eficiente para um grande projeto, você poderia me ajudar?

  • Versão : 2.8.0
  • Plataforma : Linux Mint 18.2 (construído no Ubuntu 16.04)

Comentários muito úteis

Para quem busca o resultado final que até agora alcançamos e acredita que é o caminho mais eficiente é o seguinte:

//key example "prefix*"
function getKeysByPattern(key) {
    return new Promise((resolve, reject) => {
        var stream = redis.scanStream({
            // only returns keys following the pattern of "key"
            match: key,
            // returns approximately 100 elements per call
            count: 100
        });

        var keys = [];
        stream.on('data', function (resultKeys) {
            // `resultKeys` is an array of strings representing key names
            for (var i = 0; i < resultKeys.length; i++) {
                keys.push(resultKeys[i]);
            }
        });
        stream.on('end', function () {
            resolve(keys)
        });
    })
}

//key example "prefix*"
function deleteKeysByPattern(key) {
    var stream = redis.scanStream({
        // only returns keys following the pattern of "key"
        match: key,
        // returns approximately 100 elements per call
        count: 100
    });

    var keys = [];
    stream.on('data', function (resultKeys) {
        // `resultKeys` is an array of strings representing key names
        for (var i = 0; i < resultKeys.length; i++) {
            keys.push(resultKeys[i]);
        }
    });
    stream.on('end', function () {
        redis.unlink(keys)
    });
}

//key example "prefix*"
function batchDeletionKeysByPattern(key) {
    var stream = redis.scanStream({
        // only returns keys following the pattern of "key"
        match: key,
        // returns approximately 100 elements per call
        count: 100
    });

    stream.on('data', function (resultKeys) {
        if (resultKeys.length) {
            redis.unlink(resultKeys);
        }
    });
}

O código acima é para ioredis .
Por favor, se você é alguém que conhece uma maneira melhor de fazê-lo, não hesite em compartilhar.

Todos 12 comentários

O método ao qual você vinculou é uma maneira terrível de fazer isso. KEYS não permite a produção e DEL também é bastante ineficiente. Gostaria de verificar em usar SCAN e UNLINK . Dessa forma, você pode excluir um punhado de chaves de uma vez sem amarrar o Redis.

Dito isso, esse tipo de script é com você e está além do escopo da biblioteca cliente. Vou encerrar o problema.

@ MohammedAl-Mahdawi Tenho um caso de uso semelhante em um de meus projetos e uso a implementação scanStream oferecida pela ioredis. Esta é basicamente uma maneira mais fácil de usar o comando scan : https://github.com/luin/ioredis#streamify -scanning

Se você usar SCAN e UNLINK como @stockholmux já mencionado, você poderá remover qualquer número de chaves sem bloquear o Redis.

@dirkbonhomme Muito obrigado por sua ajuda, eu realmente aprecio isso.

Segui seu conselho e usei o ioredis e criei as seguintes funções, você poderia apenas me dizer que para grandes projetos é a seguinte a maneira mais eficiente de fazê-lo ou não:

//key example "prefix*"
function getKeysByPattern(key) {
    return new Promise((resolve, reject) => {
        var stream = redis.scanStream({
            // only returns keys following the pattern of "key"
            match: key,
            // returns approximately 100 elements per call
            count: 100
        });

        var keys = [];
        stream.on('data', function (resultKeys) {
            // `resultKeys` is an array of strings representing key names
            for (var i = 0; i < resultKeys.length; i++) {
                keys.push(resultKeys[i]);
            }
        });
        stream.on('end', function () {
            resolve(keys)
        });
    })
}

//key example "prefix*"
function deleteKeysByPattern(key) {
    var stream = redis.scanStream({
        // only returns keys following the pattern of "key"
        match: key,
        // returns approximately 100 elements per call
        count: 100
    });

    var keys = [];
    stream.on('data', function (resultKeys) {
        // `resultKeys` is an array of strings representing key names
        for (var i = 0; i < resultKeys.length; i++) {
            keys.push(resultKeys[i]);
        }
    });
    stream.on('end', function () {
        redis.unlink(keys)
    });
}

@ MohammedAl-Mahdawi parece bom para mim. O único problema possível é que você carregue todas as chaves correspondentes na memória de uma vez. Se isso for um problema, você pode removê-los em lotes assim que chegarem:

stream.on('data', function (resultKeys) {
        if (resultKeys.length) {
              redis.unlink(resultKeys);
        }
    });

@dirkbonhomme e @ MohammedAl-Mahdawi Este método tem problemas de atomicidade que podem afetar você na produção.

@stockholmux Obrigado por sua ajuda, então qual é a solução certa para este problema, por favor?

Para quem busca o resultado final que até agora alcançamos e acredita que é o caminho mais eficiente é o seguinte:

//key example "prefix*"
function getKeysByPattern(key) {
    return new Promise((resolve, reject) => {
        var stream = redis.scanStream({
            // only returns keys following the pattern of "key"
            match: key,
            // returns approximately 100 elements per call
            count: 100
        });

        var keys = [];
        stream.on('data', function (resultKeys) {
            // `resultKeys` is an array of strings representing key names
            for (var i = 0; i < resultKeys.length; i++) {
                keys.push(resultKeys[i]);
            }
        });
        stream.on('end', function () {
            resolve(keys)
        });
    })
}

//key example "prefix*"
function deleteKeysByPattern(key) {
    var stream = redis.scanStream({
        // only returns keys following the pattern of "key"
        match: key,
        // returns approximately 100 elements per call
        count: 100
    });

    var keys = [];
    stream.on('data', function (resultKeys) {
        // `resultKeys` is an array of strings representing key names
        for (var i = 0; i < resultKeys.length; i++) {
            keys.push(resultKeys[i]);
        }
    });
    stream.on('end', function () {
        redis.unlink(keys)
    });
}

//key example "prefix*"
function batchDeletionKeysByPattern(key) {
    var stream = redis.scanStream({
        // only returns keys following the pattern of "key"
        match: key,
        // returns approximately 100 elements per call
        count: 100
    });

    stream.on('data', function (resultKeys) {
        if (resultKeys.length) {
            redis.unlink(resultKeys);
        }
    });
}

O código acima é para ioredis .
Por favor, se você é alguém que conhece uma maneira melhor de fazê-lo, não hesite em compartilhar.

@ MohammedAl-Mahdawi,
Estou recebendo este erro, quaisquer ideias sobre o mesmo
base de código:

let redisDel = () => {
    var key="employees*"

    return new Promise((resolve, reject) => {

        var stream = redis.scanStream({
            // only returns keys following the pattern of "key"
            match: key,
            // returns approximately 100 elements per call
            count: 100
        });

        stream.on('data', function (resultKeys) {
            if (resultKeys.length) {
                console.log(resultKeys)
                redis.unlink(resultKeys);
            }
        });
        stream.on('end', function (resultKeys) {
            resolve()
        })

    })
}

screenshot from 2019-03-05 19 28 10

alguém dá solução perfeita aqui?

@ siddhkadam1881 O comando unlink só está disponível a partir do Redis 4 https://redis.io/commands/unlink
Você provavelmente está executando uma versão mais antiga. Em vez disso, tente del .

Quero entender como a digitalização é feita ?. Acho que na solução de @MahammedAl-Mahdawi se a exclusão acontecer em lotes, há a possibilidade de que novas chaves adicionadas naquele momento que não desejamos excluir, sejam digitalizadas e excluídas. Que tal um roteiro lua?

Alguém tem alguma ideia de por que esta solução não funcionaria em um servidor ElastiCache muito simples de 1 instância, mas funciona localmente? Consigo limpar as chaves normalmente, mas se tento usar a implementação de stream, ela nunca retorna nenhuma chave no ElastiCache.

Esta página foi útil?
0 / 5 - 0 avaliações

Questões relacionadas

gpascale picture gpascale  ·  4Comentários

Stono picture Stono  ·  6Comentários

juriansluiman picture juriansluiman  ·  3Comentários

Alchemystic picture Alchemystic  ·  6Comentários

aletorrado picture aletorrado  ·  6Comentários