Відповіді:
Це неможливо , щоб зробити Redis простим .
Кейт Антірез, творець Redis:
Привіт, це не можливо, або використовувати інший ключ верхнього рівня для цього конкретного поля, або зберігати разом із поданим іншим полем із закінченням часу, отримати обидва, і нехай програма зрозуміє, чи вона все ще дійсна чи не заснована на Поточний час.
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
команду. Знову ж таки, вам потрібно врахувати ефективність цього підходу для вашого конкретного сценарію.
Ще кілька посилань:
Існує Redison java Framework, який реалізує хеш- Map
об’єкт із підтримкою TTL для входу. Він використовує hmap
і zset
об'єкти Redis під кришкою. Приклад використання:
RMapCache<Integer, String> map = redisson.getMapCache('map');
map.put(1, 30, TimeUnit.DAYS); // this entry expires in 30 days
Цей підхід є досить корисним.
Це можливо в KeyDB, що є Fork of Redis. Тому що це Fork, він повністю сумісний з Redis і працює як крапля в заміні.
Просто використовуйте команду EXPIREMEMBER. Він працює з наборами, хешами та сортованими наборами.
EXPIREMEMBER підрозділ імені ключа [час]
Ви також можете використовувати TTL та PTTL, щоб побачити термін дії
Підрозділ ключового слова TTL
Більше документації можна отримати тут: https://docs.keydb.dev/docs/commands/#expiremember
Щодо реалізації 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);
}
})
}
});
Array.filter
масивом keys
для видалення з хешу, а потім передайте його client.hdel(HASH_NAME, ...keys)
в один виклик.
const keys = Object.keys(reply).filter(key => reply[key] && JSON.parse(reply[key]).expiryTime < Date.now()); client.hdel(HASH_NAME, ...keys);
Ти можеш. Ось приклад.
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
Ви можете зберігати ключ / значення в Redis по-різному, щоб досягти цього, просто додавши до своїх ключів префікс або простір імен, наприклад, "hset_"
Отримайте ключ / значення, GET hset_key
рівнеHGET hset key
Додайте ключ / значення SET hset_key value
дорівнюєHSET hset key
Отримати всі ключі KEYS hset_*
дорівнюєHGETALL hset
Отримати всі вали потрібно в 2 ops, спочатку дістаньте всі ключі, KEYS hset_*
потім отримайте значення для кожного ключа
Додайте ключ / значення за допомогою TTL або закінчіть термін дії, що є темою питання:
SET hset_key value
EXPIRE hset_key
Примітка : KEYS
буде пошук для відповідності ключа у всій базі даних, що може вплинути на продуктивність, особливо якщо у вас велика база даних.
Примітка:
KEYS
знайде ключ для відповідності ключа у всій базі даних, що може вплинути на продуктивність, особливо якщо у вас велика база даних. хоча це SCAN 0 MATCH hset_*
може бути краще, якщо він не блокує сервер, але все-таки продуктивність є проблемою у випадку великої бази даних.
Ви можете створити нову базу даних для зберігання окремо цих ключів, які ви хочете закінчити, особливо якщо вони є невеликим набором ключів.
Дякуємо @DanFarrell, який висвітлив питання про ефективність, пов’язане з
KEYS
hashset
.. отримати O (1) множину O (1) отримати все O (n)
O(n)
кількість речей у наборі, KEYS
до кількості речей у БД.
scan 0 match namespace:*
може бути краще, доки він не блокує сервер
У нас була та сама проблема, яку обговорювали тут.
У нас є хеш Redis, ключ до хеш-записів (пари імен / значень), і нам потрібно було провести окремі строки закінчення терміну дії для кожного запису хешу.
Ми реалізували це, додавши n байт даних префікса, що містять кодовану інформацію про термін дії, коли ми пишемо значення введення хешу, а також встановлюємо ключ, який закінчується в момент, який міститься у записуваному значенні.
Потім, прочитавши, розшифровуємо префікс і перевіряємо на термін дії. Це додаткові накладні витрати, проте, показання все ще O (n), і весь ключ закінчується, коли закінчився останній хеш-запис.
Ви можете використовувати сповіщення Redis Keyspace за допомогою psubscribe
та "__keyevent@<DB-INDEX>__:expired"
.
При цьому щоразу, коли ключ закінчується, ви отримуватимете повідомлення, опубліковане на вашому з’єднанні redis.
Що стосується вашого питання, то ви створюєте тимчасовий "звичайний" ключ, використовуючи set
час закінчення в с / мс. Він повинен відповідати імені ключа, який ви бажаєте видалити у своєму наборі.
Оскільки ваш тимчасовий ключ буде опублікований у вашому з’єднанні redis, утримуючи його, "__keyevent@0__:expired"
коли термін його дії закінчився, ви можете легко видалити свій ключ із початкового набору, оскільки повідомлення матиме ім'я ключа.
Простий приклад на практиці на цій сторінці: https://medium.com/@micah1powell/using-redis-keyspace-notifications-for-a-reminder-service-with-node-c05047befec3
doc: https://redis.io/topics/notifications (шукайте прапор xE)
Ви можете використовувати сортований набір у redis, щоб отримати контейнер TTL з часовою міткою як оцінка. Наприклад, щоразу, коли ви вставляєте рядок події у набір, ви можете встановити його результат на час події. Таким чином, ви можете отримати дані будь-якого часового вікна, зателефонувавши
zrangebyscore "your set name" min-time max-time
Більше того, ми можемо закінчити термін дії, використовуючи zremrangebyscore "your set name" min-time max-time
для видалення старих подій.
Єдиним недоліком тут є те, що ви повинні вести прибирання з аутсайдерів, щоб підтримувати розмір набору.
Ви можете швидко закінчити хеш Redis, наприклад, використовуючи python
import redis
conn = redis.Redis('localhost')
conn.hmset("hashed_user", {'name': 'robert', 'age': 32})
conn.expire("hashed_user", 10)
Це закінчаться всі дочірні ключі в хеш hashed_user через 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)
hset
дитини закінчується не повністю hset
.