Як "ДОСЛІДЖИТИ" дочірню клавішу "HSET" у червоному кольорі?


107

Мені потрібно закінчити термін дії всіх ключів у хеді Redis, які старші 1 місяця.

Відповіді:


117

Це неможливо , щоб зробити Redis простим .

Кейт Антірез, творець Redis:

Привіт, це не можливо, або використовувати інший ключ верхнього рівня для цього конкретного поля, або зберігати разом із поданим іншим полем із закінченням часу, отримати обидва, і нехай програма зрозуміє, чи вона все ще дійсна чи не заснована на Поточний час.


8
ось чому redis - це така дивовижна програма. вони знають, де це зробити просто
tObi

20

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

Існує 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

Цей підхід є досить корисним.


але як можна створити карту? тому що я не знаходжу жодного підручника чи методу створення / набору
FaNaT

@ ZoltánNémeth У картці Redis створюється автоматично при введенні першого значення.
Микита Кокшаров

3

Це можливо в KeyDB, що є Fork of Redis. Тому що це Fork, він повністю сумісний з Redis і працює як крапля в заміні.

Просто використовуйте команду EXPIREMEMBER. Він працює з наборами, хешами та сортованими наборами.

EXPIREMEMBER підрозділ імені ключа [час]

Ви також можете використовувати TTL та PTTL, щоб побачити термін дії

Підрозділ ключового слова TTL

Більше документації можна отримати тут: https://docs.keydb.dev/docs/commands/#expiremember


2

Щодо реалізації 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);
подвійний горез

1

Ти можеш. Ось приклад.

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

24
Я не думаю, що він хоче закінчувати термін дії всіх ключів у хеші, скоріше всі ключі в хеші старші ніж на 1 місяць , тому лише деякі з них. Який AFAIK неможливий.
UpTheCreek

1
ІМХО питання, давайте припустимо це. Тож Джонатан отримує +1 від мене, адже він мені допоміг! Дякую!
longliveenduro

як ви закінчуєте терміни "f1" та "f2"?
vgoklani

4
Це не дає відповіді на питання або взагалі не допомагає. Необхідність полягає в тому, щоб закінчити термін дії елементів у хеші, а не самого хеша.
Рон

@UpTheCreek Дякую!
Джонатан Кім,

1

Ви можете зберігати ключ / значення в 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


1
просто пам’ятайте, що це суттєва зміна характеристик продуктивності
Даніель Фаррелл

як! якщо говорити про часові складності, то всі ці операції мають однакову складність часу, як hashset.. отримати O (1) множину O (1) отримати все O (n)
Мухаммед Соліман

"розглядайте KEYS як команду, яку слід використовувати лише у виробничих середовищах з особливою обережністю." redis.io/commands/KEYS . HGETALL - це O(n)кількість речей у наборі, KEYSдо кількості речей у БД.
Даніель Фаррелл

це правда, scan 0 match namespace:*може бути краще, доки він не блокує сервер
Мухаммад Соліман

1
також розділіть ці клавіші, якщо вони невеликі, до різної бази даних. дякую @DanFarrell
Мухаммад Соліман

1

У нас була та сама проблема, яку обговорювали тут.

У нас є хеш Redis, ключ до хеш-записів (пари імен / значень), і нам потрібно було провести окремі строки закінчення терміну дії для кожного запису хешу.

Ми реалізували це, додавши n байт даних префікса, що містять кодовану інформацію про термін дії, коли ми пишемо значення введення хешу, а також встановлюємо ключ, який закінчується в момент, який міститься у записуваному значенні.

Потім, прочитавши, розшифровуємо префікс і перевіряємо на термін дії. Це додаткові накладні витрати, проте, показання все ще O (n), і весь ключ закінчується, коли закінчився останній хеш-запис.


0

Ви можете використовувати сповіщення 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)


0

Ви можете використовувати сортований набір у redis, щоб отримати контейнер TTL з часовою міткою як оцінка. Наприклад, щоразу, коли ви вставляєте рядок події у набір, ви можете встановити його результат на час події. Таким чином, ви можете отримати дані будь-якого часового вікна, зателефонувавши zrangebyscore "your set name" min-time max-time

Більше того, ми можемо закінчити термін дії, використовуючи zremrangebyscore "your set name" min-time max-timeдля видалення старих подій.

Єдиним недоліком тут є те, що ви повинні вести прибирання з аутсайдерів, щоб підтримувати розмір набору.


-1

Ви можете швидко закінчити хеш 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)

6
Питання в тому, що термін дії hsetдитини закінчується не повністю hset.
thangdc94

не відповідає на поставлене запитання
peteclark3
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.