Мне нужно закончить все ключи в redis хэш, которые старше 1 месяца.
Как "EXPIRE" дочерний ключ "HSET" в redis?
Ответ 1
Это невозможно, ради простоты Redis.
Квот Антирез, создатель Redis:
Привет, это невозможно, либо использовать другой ключ верхнего уровня для этого конкретного поля, либо сохранить вместе с поданным другим полем со временем истечения, получить оба и позволить приложению понять, если он все еще действителен или не основан на Текущее время.
Ответ 2
Redis не поддерживает наличие TTL
для хэшей, кроме верхней клавиши, что приведет к истечению всего хэша. Если вы используете сегментированный кластер, вы можете использовать другой подход. Этот подход не может быть полезен во всех сценариях, и характеристики производительности могут отличаться от ожидаемых. Еще стоит упомянуть:
При наличии хеша структура в основном выглядит следующим образом:
hash_top_key
- child_key_1 -> some_value
- child_key_2 -> some_value
...
- child_key_n -> some_value
Поскольку мы хотим добавить TTL
к дочерним клавишам, мы можем переместить их в верхние клавиши. Главное, чтобы ключ теперь был комбинацией hash_top_key
и дочернего ключа:
{hash_top_key}child_key_1 -> some_value
{hash_top_key}child_key_2 -> some_value
...
{hash_top_key}child_key_n -> some_value
Мы специально используем обозначение {}
. Это позволяет всем этим клавишам находиться в одном hash slot
. Вы можете прочитать больше об этом здесь: https://redis.io/topics/cluster-tutorial
Теперь, если мы хотим выполнить ту же операцию с хешами, мы могли бы сделать:
HDEL hash_top_key child_key_1 => DEL {hash_top_key}child_key_1
HGET hash_top_key child_key_1 => GET {hash_top_key}child_key_1
HSET hash_top_key child_key_1 some_value => SET {hash_top_key}child_key_1 some_value [some_TTL]
HGETALL hash_top_key =>
keyslot = CLUSTER KEYSLOT {hash_top_key}
keys = CLUSTER GETKEYSINSLOT keyslot n
MGET keys
Интересным здесь является HGETALL
. Сначала мы получаем hash slot
для всех наших дочерних ключей. Затем мы получаем ключи для этого конкретного hash slot
и, наконец, получаем значения. Здесь нужно быть осторожным, поскольку для этого n
может быть больше ключей hash slot
, а также могут быть ключи, которые нам не интересны, но у них одинаковые hash slot
. На самом деле мы могли бы написать сценарий Lua
для выполнения этих действий на сервере, выполнив команду EVAL
или EVALSHA
. Опять же, вы должны принять во внимание эффективность этого подхода для вашего конкретного сценария.
Еще несколько ссылок:
Ответ 3
Существует Java-инфраструктура Redisson, которая реализует хэш-объект Map
с поддержкой записи TTL. Он использует hmap
и zset
Redis объекты под капотом. Пример использования:
RMapCache<Integer, String> map = redisson.getMapCache('map');
map.put(1, 30, TimeUnit.DAYS); // this entry expires in 30 days
Этот подход весьма полезен.
Ответ 4
Что касается реализации NodeJS, я добавил пользовательское поле expiryTime
в объект, который я сохраняю в HASH. Затем по истечении определенного периода времени я очищаю устаревшие записи HASH, используя следующий код:
client.hgetall(HASH_NAME, function(err, reply) {
if (reply) {
Object.keys(reply).forEach(key => {
if (reply[key] && JSON.parse(reply[key]).expiryTime < (new Date).getTime()) {
client.hdel(HASH_NAME, key);
}
})
}
});
Ответ 5
Вы можете хранить ключи/значения в Redis по-разному, чтобы достичь этого, просто добавив префикс или пространство имен к своим ключам, когда вы сохраняете их, например, "hset_"
-
Получить ключ/значение
GET hset_key
равноHGET hset key
-
Добавить ключ/значение
SET hset_key value
равноSET hset_key value
HSET hset key
-
Получить все ключи
KEYS hset_*
равноHGETALL hset
-
Получить все значения нужно за 2 операции, сначала получить все ключи
KEYS hset_*
затем получить значение для каждого ключа -
Добавьте ключ/значение с TTL или expire, что является темой вопроса:
SET hset_key value
EXPIRE hset_key
Примечание. KEYS
поиск соответствия ключа во всей базе данных, что может повлиять на производительность, особенно если у вас большая база данных.
Замечания:
-
KEYS
проверит соответствие ключа во всей базе данных, что может повлиять на производительность, особенно если у вас большая база данных. в то время какSCAN 0 MATCH hset_*
может быть лучше, если он не блокирует сервер, но все же производительность является проблемой в случае большой базы данных. -
Вы можете создать новую базу данных для отдельного хранения этих ключей, срок действия которых вы хотите истечь, особенно если они представляют собой небольшой набор ключей.
Спасибо @DanFarrell, который выделил проблему производительности, связанную с
KEYS
Ответ 6
Вы можете. Вот пример.
redis 127.0.0.1:6379> hset key f1 1
(integer) 1
redis 127.0.0.1:6379> hset key f2 2
(integer) 1
redis 127.0.0.1:6379> hvals key
1) "1"
2) "1"
3) "2"
redis 127.0.0.1:6379> expire key 10
(integer) 1
redis 127.0.0.1:6379> hvals key
1) "1"
2) "1"
3) "2"
redis 127.0.0.1:6379> hvals key
1) "1"
2) "1"
3) "2"
redis 127.0.0.1:6379> hvals key
Используйте EXPIRE или EXPIREAT команда.
Если вы хотите истечь определенные ключи в хеш старше, чем 1 месяц. Это невозможно. Команда redis expire предназначена для всех ключей в хеше. Если вы установите ежедневный хеш-ключ, вы можете установить время жизни клавиш.
hset key-20140325 f1 1
expire key-20140325 100
hset key-20140325 f1 2
Ответ 7
Вы можете легко истечь хэши Redis, например, используя python
import redis
conn = redis.Redis('localhost')
conn.hmset("hashed_user", {'name': 'robert', 'age': 32})
conn.expire("hashed_user", 10)
Это истечет срок действия всех дочерних ключей в hash_hser через 10 секунд
то же самое от redis-cli,
127.0.0.1:6379> HMSET testt username wlc password P1pp0 age 34
OK
127.0.0.1:6379> hgetall testt
1) "username"
2) "wlc"
3) "password"
4) "P1pp0"
5) "age"
6) "34"
127.0.0.1:6379> expire testt 10
(integer) 1
127.0.0.1:6379> hgetall testt
1) "username"
2) "wlc"
3) "password"
4) "P1pp0"
5) "age"
6) "34"
через 10 секунд
127.0.0.1:6379> hgetall testt
(empty list or set)
Ответ 8
Вы можете использовать Redis Keyspace Notification, используя psubscribe
и "[email protected]<DB-INDEX>__:expired"
.
При этом каждый раз, когда истекает срок действия ключа, вы будете публиковать сообщение о своем подключении к Redis.
Относительно вашего вопроса в основном вы создаете временный "нормальный" ключ, используя set
со временем истечения в с/мс. Он должен соответствовать названию ключа, который вы хотите удалить в своем наборе.
Поскольку ваш временный ключ будет опубликован в вашем подключении redis, содержащем "[email protected]__:expired"
когда он истек, вы можете легко удалить свой ключ из исходного набора, так как в сообщении будет указано имя ключа.
Простой пример из практики на этой странице: https://medium.com/@micah1powell/using-redis-keyspace-notifications-for-a-reminder-service-with-node-c05047befec3
doc: https://redis.io/topics/notifications (ищите флаг xE)
Ответ 9
Вы можете использовать Sorted Set в Redis, чтобы получить контейнер TTL с отметкой времени в качестве оценки. Например, всякий раз, когда вы вставляете строку события в набор, вы можете установить ее счет на время события. Таким образом, вы можете получить данные любого временного окна, вызвав zrangebyscore "your set name" min-time max-time
Более того, мы можем сделать истечение срока действия, используя zremrangebyscore "your set name" min-time max-time
для удаления старых событий.
Единственным недостатком здесь является то, что вы должны вести домашнюю работу из аутсайдерского процесса, чтобы поддерживать размер набора.
Ответ 10
Здесь обсуждалась та же проблема.
У нас есть хэш Redis, ключ к хеш-записям (пары имя/значение), и нам нужно было хранить индивидуальное время истечения для каждой хеш-записи.
Мы реализовали это, добавив n байтов данных префикса, содержащих закодированную информацию об истечении срока действия, когда мы записываем значения хеш-записи, мы также устанавливаем срок действия ключа в момент, содержащийся в записываемом значении.
Затем, при чтении, мы декодируем префикс и проверяем его срок действия. Это дополнительные накладные расходы, однако чтения по-прежнему O (n) и весь ключ истечет, когда истек срок действия последней записи хеша.