#javascript #node.js #redis
#javascript #node.js #redis
Вопрос:
Я пытаюсь показать представление всех ключей, которые выглядят как ‘myprefix: *’ и их TTL. Затем я могу разрешить администратору либо истечь срок действия ключа, либо «коснуться его» (т. Е. Добавить час к истечению срока действия).
Я могу использовать redisClient.keys('myprefix:*', (err, keys) => {})
для получения своих ключей, но redisClient.ttl
команда принимает только один ключ, а не массив. Я не хочу перебирать массив и отправлять n ttl
команд.
Я знаю, что, вероятно, могу использовать multi
для отправки транзакции ttl
команд, но мне интересно, есть ли лучший способ (в JavaScript, а не в оболочке) получить все ключи и их TTL в одной / двух командах?
Ответ №1:
Поскольку Redis встраивает интерпретатор Lua, решением было бы создать сценарий Redis Lua, подобный этому:
local keys = redis.call('keys','myprefix:*')
local result = {}
for i,k in ipairs(keys) do
local ttl = redis.call('ttl', k)
result[i] = {ttl}
end
return result
Используя ioredis, вы можете упростить объявление сценариев Redis Lua в NodeJS:
var Redis = require('ioredis');
var redis = new Redis();
// This will define a command getTtls:
redis.defineCommand('getTtls', {
numberOfKeys: 1,
lua: "local keys = redis.call('keys', KEYS[1]..':*')n local result = {}n for i,k in ipairs(keys) do n local ttl = redis.call('ttl', k)n result[i] = {ttl}n endn return result"
});
// now invoke this new command, giving the prefix as a parameter
redis.getTtls('myprefix', function (err, result) {
console.log(result);
});
Сценарий определен в вашем приложении NodeJS, но выполняется Redis.
Не забывайте, что использование команды KEYS в рабочей среде часто является плохой идеей, поскольку она сканирует всю базу данных за одну операцию и, таким образом, делает ваш экземпляр Redis невосприимчивым к другим запросам в течение времени, которое может быть довольно долгим (это зависит от количества ключей в вашей базе данных). Если это проблема в вашем случае использования, вы, вероятно, захотите вместо этого использовать команду СКАНИРОВАНИЯ.
Комментарии:
1. В чем смысл использования use LUA? Код уже написан на JavaScript. Логика вашего скрипта, похоже, та же: вызов
keys
, итерация и вызовttl
. Итак, для N ключей у нас будет N ! сетевые отключения — это то, чего я пытаюсь избежать.2. Redis встраивает интерпретатор Lua. Этот скрипт будет передан в Redis, который выполнит его как атомарную команду, а затем вернет результат. Посмотрите на EVAL для получения дополнительной информации.
3. Просто для ясности, в моем решении есть только один запрос к Redis.
4. Спасибо, что нашли время ответить. Я пытаюсь решить это строго в JS и без добавления другого кода dependency (
ioredis
) или LUA.
Ответ №2:
Наконец-то прибегли к использованию multi
. Я понимаю, как использовать keys
, так и multi
настоятельно не рекомендуется в производстве. Но количество ключей, с которыми я сейчас работаю, довольно мало (менее 10).
Использование keys
multi
для получения ttl
из N ключей приводит к 2 отключениям сети, а не к N 1.
По мере роста я буду пересматривать решение. Я опубликовал свой код ниже, если он кому-нибудь понадобится:
let getKeys = prefix => {
return new Promise((resolve, reject) => {
redisClient.keys(`${prefix}:*`), (err, keys) => {
if(err) {
reject(err)
}
else {
let multi = redisClient.multi();
keys.forEach(k => multi.ttl(k));
multi.exec((err2, ttls) => {
if(err2) {
reject(err2);
}
else {
let result = keys.map((k, i) => ({key: k.replace(`${prefix}:`, ''), ttl: ttls[i]}));
resolve(result);
}
});
}
});
});
};
Это дает массив:
[ { key: '05460a69f7c0d313b7edfcca4f267cee', ttl: 3034 },
{ key: 'b1065bfa82408a10e2d2d0a50df1eef9', ttl: 3031 },
{ key: 'c3aeced2ef08f1c728f0b367c50a962a', ttl: 3019 } ]