Node-redis: Эффективный способ удаления ключей по шаблону

Созданный на 5 мар. 2018  ·  12Комментарии  ·  Источник: NodeRedis/node-redis

Я работаю над большим проектом и в некоторых местах мне приходится удалять ключи по шаблону, например, я хочу удалить все ключи, начинающиеся с filterProducts

Я сделал поиск в Google и нашел несколько способов сделать это, например, метод, описанный в этой статье.

Но я не знаю, какой из них наиболее эффективен для большого проекта, не могли бы вы мне помочь?

  • Версия : 2.8.0
  • Платформа : Linux Mint 18.2 (построена на Ubuntu 16.04)

Самый полезный комментарий

Для тех, кто ищет окончательный результат, которого мы до сих пор достигли, и считает, что это наиболее эффективный способ, следующий:

//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);
        }
    });
}

Приведенный выше код предназначен для ioredis .
Пожалуйста, если вы знаете, как это лучше сделать, не стесняйтесь делиться.

Все 12 Комментарий

Метод, с которым вы связались, - довольно ужасный способ справиться с этим. KEYS не подходит для производства, а DEL также довольно неэффективен. Я бы проверял, используя SCAN и UNLINK . Таким образом, вы можете удалить несколько ключей за раз, не связывая Redis.

При этом такой тип сценария зависит от вас и выходит за рамки клиентской библиотеки. Я закрою вопрос.

@ MohammedAl-Mahdawi У меня есть аналогичный вариант использования в одном из моих проектов, и я использую реализацию scanStream предложенную ioredis. По сути, это более простой способ использования команды scan : https://github.com/luin/ioredis#streamify -scanning

Если вы используете SCAN и UNLINK такие как уже упомянутый @stockholmux , вы сможете удалить любое количество ключей, не блокируя Redis.

@dirkbonhomme Большое спасибо за вашу помощь, я очень ценю это.

Я последовал вашему совету, использовал ioredis и создал следующие функции. Не могли бы вы сказать мне, что для больших проектов это наиболее эффективный способ сделать это или нет:

//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 мне нравится. Единственная возможная проблема заключается в том, что вы сразу загрузите в память все совпадающие ключи. Если это проблема, вы можете удалять их группами, как только они поступят:

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

@dirkbonhomme и @ MohammedAl-Mahdawi У этого метода есть проблемы с атомарностью, которые могут вас укусить при производстве.

@stockholmux Спасибо за вашу помощь, пожалуйста, каково правильное решение этой проблемы?

Для тех, кто ищет окончательный результат, которого мы до сих пор достигли, и считает, что это наиболее эффективный способ, следующий:

//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);
        }
    });
}

Приведенный выше код предназначен для ioredis .
Пожалуйста, если вы знаете, как это лучше сделать, не стесняйтесь делиться.

@ Мохаммед Аль-Махдави,
Я получаю эту ошибку, любые идеи по поводу того же
кодовая база:

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

кто-нибудь дает здесь идеальное решение?

@ siddhkadam1881 Команда unlink доступна только с Redis 4 https://redis.io/commands/unlink
Вероятно, вы используете более старую версию. Вместо этого попробуйте del .

Я хочу понять, как выполняется сканирование ?. Я думаю, что в решении @ MohammedAl-Mahdawi, если удаление происходит партиями, есть ли вероятность, что новые ключи, добавленные за это время, которые мы не хотим удалять, будут сканироваться и удаляться. Как насчет сценария lua?

У кого-нибудь есть идеи, почему это решение не работает на очень простом сервере ElastiCache с одним экземпляром, но работает локально? Я могу нормально очищать ключи, но если я попытаюсь использовать реализацию потока, она просто никогда не вернет никаких ключей в ElastiCache.

Была ли эта страница полезной?
0 / 5 - 0 рейтинги