Я работаю над большим проектом и в некоторых местах мне приходится удалять ключи по шаблону, например, я хочу удалить все ключи, начинающиеся с filterProducts
Я сделал поиск в Google и нашел несколько способов сделать это, например, метод, описанный в этой статье.
Но я не знаю, какой из них наиболее эффективен для большого проекта, не могли бы вы мне помочь?
Метод, с которым вы связались, - довольно ужасный способ справиться с этим. 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()
})
})
}
кто-нибудь дает здесь идеальное решение?
@ siddhkadam1881 Команда unlink доступна только с Redis 4 https://redis.io/commands/unlink
Вероятно, вы используете более старую версию. Вместо этого попробуйте del
.
Я хочу понять, как выполняется сканирование ?. Я думаю, что в решении @ MohammedAl-Mahdawi, если удаление происходит партиями, есть ли вероятность, что новые ключи, добавленные за это время, которые мы не хотим удалять, будут сканироваться и удаляться. Как насчет сценария lua?
У кого-нибудь есть идеи, почему это решение не работает на очень простом сервере ElastiCache с одним экземпляром, но работает локально? Я могу нормально очищать ключи, но если я попытаюсь использовать реализацию потока, она просто никогда не вернет никаких ключей в ElastiCache.
Самый полезный комментарий
Для тех, кто ищет окончательный результат, которого мы до сих пор достигли, и считает, что это наиболее эффективный способ, следующий:
Приведенный выше код предназначен для ioredis .
Пожалуйста, если вы знаете, как это лучше сделать, не стесняйтесь делиться.