Bagaimana cara "MENGELUARKAN" kunci anak "HSET" di redis?

108

Saya perlu menghentikan semua kunci dalam hash redis, yang lebih lama dari 1 bulan.

aieven
sumber

Jawaban:

117

Ini tidak mungkin , demi menjaga kesederhanaan Redis .

Quoth Antirez, pencipta Redis:

Hai, itu tidak mungkin, gunakan kunci tingkat atas yang berbeda untuk bidang spesifik itu, atau simpan bersama dengan bidang lain yang diajukan dengan waktu kedaluwarsa, ambil keduanya, dan biarkan aplikasi memahami apakah itu masih valid atau tidak berdasarkan waktu saat ini.

Supr
sumber
8
inilah mengapa redis adalah perangkat lunak yang luar biasa. mereka tahu di mana harus membuatnya sederhana
tObi
20

Redis tidak mendukung memiliki TTL hash selain kunci teratas, yang akan menghentikan seluruh hash. Jika Anda menggunakan cluster yang dipecah, ada pendekatan lain yang dapat Anda gunakan. Pendekatan ini tidak dapat berguna di semua skenario dan karakteristik kinerja mungkin berbeda dari yang diharapkan. Masih layak untuk disebutkan:

Saat memiliki hash, strukturnya pada dasarnya terlihat seperti:

hash_top_key
  - child_key_1 -> some_value
  - child_key_2 -> some_value
  ...
  - child_key_n -> some_value

Karena kami ingin menambahkan TTLkunci anak, kami dapat memindahkannya ke kunci atas. Poin utamanya adalah bahwa kuncinya sekarang harus merupakan kombinasi dari hash_top_keydan kunci anak:

{hash_top_key}child_key_1 -> some_value
{hash_top_key}child_key_2 -> some_value
...
{hash_top_key}child_key_n -> some_value

Kami menggunakan {}notasi dengan sengaja. Ini memungkinkan semua kunci tersebut berada di tempat yang sama hash slot. Anda dapat membaca lebih lanjut di sini: https://redis.io/topics/cluster-tutorial

Sekarang jika kita ingin melakukan operasi hash yang sama, kita dapat melakukan:

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

Yang menarik di sini adalah HGETALL. Pertama kita mendapatkan hash slotkunci untuk semua anak kita. Kemudian kami mendapatkan kunci untuk itu hash slotdan akhirnya kami mengambil nilainya. Kita perlu berhati-hati di sini karena mungkin ada lebih dari nkunci untuk itu hash slotdan juga mungkin ada kunci yang tidak kita minati tetapi memiliki kunci yang sama hash slot. Kami sebenarnya dapat menulis Luaskrip untuk melakukan langkah-langkah tersebut di server dengan menjalankan perintah EVALatau EVALSHA. Sekali lagi, Anda perlu mempertimbangkan kinerja pendekatan ini untuk skenario khusus Anda.

Beberapa referensi lagi:

hveiga
sumber
Pendekatan ini menggunakan lebih banyak memori daripada kunci sederhana dengan waktu kedaluwarsa.
VasileM
3

Ada framework java Redisson yang mengimplementasikan Mapobjek hash dengan dukungan TTL entri. Ia menggunakan hmapdan zsetobjek Redis di bawah tenda. Contoh penggunaan:

RMapCache<Integer, String> map = redisson.getMapCache('map');
map.put(1, 30, TimeUnit.DAYS); // this entry expires in 30 days

Pendekatan ini cukup berguna.

Nikita Koksharov
sumber
tapi bagaimana Anda bisa membuat peta? karena saya tidak menemukan tutorial atau metode buat / set
FaNaT
@ ZoltánNémeth Dalam peta Redis dibuat secara otomatis ketika nilai pertama dimasukkan.
Nikita Koksharov
3

Ini dimungkinkan di KeyDB yang merupakan Fork of Redis. Karena ini adalah Fork yang sepenuhnya kompatibel dengan Redis dan berfungsi sebagai pengganti pengganti.

Cukup gunakan perintah EXPIREMEMBER. Ia bekerja dengan set, hashes, dan set yang diurutkan.

EXPIREMEMBER subkunci nama kunci [waktu]

Anda juga dapat menggunakan TTL dan PTTL untuk melihat kedaluwarsa

Subkunci nama kunci TTL

Dokumentasi selengkapnya tersedia di sini: https://docs.keydb.dev/docs/commands/#expiremember

John Sully
sumber
2

Mengenai implementasi NodeJS, saya telah menambahkan expiryTimebidang kustom di objek yang saya simpan di HASH. Kemudian setelah jangka waktu tertentu, saya menghapus entri HASH yang kadaluwarsa dengan menggunakan kode berikut:

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);
            }
        })
    }
});
George I. Tsopouridis
sumber
Anda dapat membuat ini lebih efisien dengan menggunakan Array.filteruntuk membuat larik keysuntuk dihapus dari hash lalu meneruskannya ke client.hdel(HASH_NAME, ...keys)dalam satu panggilan.
doublesharp
const keys = Object.keys(reply).filter(key => reply[key] && JSON.parse(reply[key]).expiryTime < Date.now()); client.hdel(HASH_NAME, ...keys);
doublesharp
1

Kamu bisa. Berikut ini contohnya.

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

Gunakan perintah EXPIRE atau EXPIREAT .

Jika Anda ingin mengakhiri kunci tertentu di hash lebih lama dari 1 bulan. Ini tidak mungkin. Perintah redis expire adalah untuk semua kunci dalam hash. Jika Anda mengatur kunci hash harian, Anda dapat mengatur waktu kunci untuk hidup.

hset key-20140325 f1 1
expire key-20140325 100
hset key-20140325 f1 2
Jonathan Kim
sumber
24
Saya tidak berpikir dia ingin mengakhiri semua kunci dalam hash, melainkan semua kunci dalam hash yang lebih tua dari 1 bulan , jadi hanya beberapa dari mereka. AFAIK mana yang tidak memungkinkan.
UpTheCreek
1
IMHO pertanyaannya mari kita asumsikan ini. Jadi Jonathan mendapat +1 dari saya, karena dia membantu saya! Terima kasih!
longliveenduro
bagaimana Anda mengakhiri "f1" dan "f2"?
vgoklani
4
Ini tidak menjawab pertanyaan atau membantu sama sekali. Yang dibutuhkan adalah mengakhiri elemen dalam hash, bukan hash itu sendiri.
Ron
@UpTheCreek Terima kasih!
Jonathan Kim
1

Anda dapat menyimpan kunci / nilai di Redis secara berbeda untuk melakukannya, hanya dengan menambahkan awalan atau namespace ke kunci Anda saat Anda menyimpannya, misalnya "hset_"

  • Dapatkan kunci / nilai GET hset_keysama denganHGET hset key

  • Tambahkan kunci / nilai SET hset_key valuesama denganHSET hset key

  • Dapatkan semua kunci KEYS hset_*sama denganHGETALL hset

  • Mendapatkan semua vals harus dilakukan dalam 2 ops, pertama-tama dapatkan semua kunci KEYS hset_*lalu dapatkan nilai untuk setiap kunci

  • Tambahkan kunci / nilai dengan TTL atau kedaluwarsa yang merupakan topik pertanyaan:

 SET hset_key value
 EXPIRE hset_key

Catatan : KEYSakan mencari kunci yang cocok di seluruh database yang dapat mempengaruhi kinerja terutama jika Anda memiliki database besar.

catatan:

  • KEYSakan mencari untuk mencocokkan kunci di seluruh database yang dapat mempengaruhi kinerja terutama jika Anda memiliki database yang besar. sementara SCAN 0 MATCH hset_*mungkin lebih baik selama tidak memblokir server tetapi kinerja masih menjadi masalah jika database besar.

  • Anda dapat membuat database baru untuk menyimpan secara terpisah kunci-kunci ini yang Anda ingin kedaluwarsa terutama jika mereka adalah sekumpulan kecil kunci.

Terima kasih kepada @DanFarrell yang menyoroti masalah kinerja terkait KEYS

Muhammad Soliman
sumber
1
Sadarilah ini adalah perubahan signifikan pada karakteristik kinerja
Daniel Farrell
bagaimana! jika Anda berbicara tentang kompleksitas waktu, semua operasi ini memiliki kompleksitas waktu yang sama dengan hashset.. dapatkan O (1) himpunan O (1) dapatkan semua O (n)
Muhammad Soliman
"pertimbangkan KEYS sebagai perintah yang hanya boleh digunakan di lingkungan produksi dengan sangat hati-hati." redis.io/commands/KEYS . HGETALL adalah O(n)untuk sejumlah hal di himpunan, KEYSke jumlah hal di DB.
Daniel Farrell
itu benar, scan 0 match namespace:*mungkin lebih baik selama tidak memblokir server
Muhammad Soliman
1
juga, pisahkan kunci-kunci ini, jika mereka kecil, ke database yang berbeda. terima kasih @Danarrell
Muhammad Soliman
1

Kami memiliki masalah yang sama dibahas di sini.

Kami memiliki hash Redis, kunci entri hash (pasangan nama / nilai), dan kami perlu menahan waktu kedaluwarsa individu pada setiap entri hash.

Kami menerapkan ini dengan menambahkan n byte data awalan yang berisi informasi kedaluwarsa yang dikodekan ketika kami menulis nilai entri hash, kami juga menyetel kunci untuk kedaluwarsa pada waktu yang terdapat dalam nilai yang sedang ditulis.

Kemudian, saat membaca, kami memecahkan kode awalan dan memeriksa kedaluwarsa. Ini adalah overhead tambahan, namun, pembacaannya masih O (n) dan seluruh kunci akan kedaluwarsa ketika entri hash terakhir telah kedaluwarsa.

MikeZ
sumber
0

Anda dapat menggunakan Redis Keyspace Notifications dengan menggunakan psubscribedan "__keyevent@<DB-INDEX>__:expired".

Dengan itu, setiap kali kunci itu kedaluwarsa, Anda akan mendapatkan pesan yang diterbitkan pada koneksi redis Anda.

Mengenai pertanyaan Anda pada dasarnya Anda membuat kunci "normal" sementara menggunakan setwaktu kedaluwarsa dalam s / ms. Ini harus cocok dengan nama kunci yang ingin Anda hapus di set Anda.

Karena kunci sementara Anda akan dipublikasikan ke koneksi redis Anda yang menahan "__keyevent@0__:expired"ketika kadaluwarsa, Anda dapat dengan mudah menghapus kunci Anda dari set asli Anda karena pesan akan memiliki nama kunci.

Contoh sederhana dalam praktiknya di halaman itu: https://medium.com/@micah1powell/using-redis-keyspace-notifications-for-a-reminder-service-with-node-c05047befec3

doc: https://redis.io/topics/notifications (cari bendera xE)

solarissmoke
sumber
0

Anda dapat menggunakan Set yang Diurutkan dalam redis untuk mendapatkan wadah TTL dengan stempel waktu sebagai skor. Misalnya, setiap kali Anda memasukkan string acara ke dalam set, Anda dapat menyetel skornya ke waktu acara. Dengan demikian Anda bisa mendapatkan data jendela waktu kapan saja dengan menelepon zrangebyscore "your set name" min-time max-time

Selain itu, kami dapat melakukan kedaluwarsa dengan menggunakan zremrangebyscore "your set name" min-time max-timeuntuk menghapus acara lama.

Satu-satunya kelemahan di sini adalah Anda harus melakukan pembenahan dari proses orang luar untuk mempertahankan ukuran set.

mojians
sumber
-1

Anda dapat berakhir Redis hash dalam kemudahan, Misalnya menggunakan python

import redis
conn = redis.Redis('localhost')
conn.hmset("hashed_user", {'name': 'robert', 'age': 32})
conn.expire("hashed_user", 10)

Ini akan menghentikan semua kunci anak dalam hash hashed_user setelah 10 detik

sama dari 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"

setelah 10 detik

127.0.0.1:6379> hgetall testt
(empty list or set)
Thomas John
sumber
7
Pertanyaannya adalah tentang hsetanak kadaluarsa bukan seluruhnya hset.
thangdc94
tidak menjawab pertanyaan yang diajukan
peteclark3