Как получить TTL нескольких ключей Redis из узла

#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 } ]