จะ“ EXPIRE” คีย์ลูก“ HSET” ใน redis ได้อย่างไร?


109

ฉันต้องการให้คีย์ทั้งหมดในแฮช redis หมดอายุซึ่งเก่ากว่า 1 เดือน

คำตอบ:


117

นี้เป็นไปไม่ได้เพื่อประโยชน์ของการรักษา Redis ง่าย

Quoth Antirez ผู้สร้าง Redis:

สวัสดีเป็นไปไม่ได้ให้ใช้คีย์ระดับบนสุดที่แตกต่างกันสำหรับฟิลด์นั้น ๆ หรือจัดเก็บพร้อมกับฟิลด์อื่นที่ยื่นพร้อมเวลาหมดอายุดึงข้อมูลทั้งสองและแจ้งให้แอปพลิเคชันเข้าใจว่ายังคงถูกต้องหรือไม่ขึ้นอยู่กับ เวลาปัจจุบัน


8
นี่คือเหตุผลที่ redis เป็นซอฟต์แวร์ที่ยอดเยี่ยม พวกเขารู้ว่าจะทำให้มันง่าย
ตรงไหน

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อีกครั้งคุณต้องคำนึงถึงประสิทธิภาพของแนวทางนี้สำหรับสถานการณ์เฉพาะของคุณ

ข้อมูลอ้างอิงเพิ่มเติม:


วิธีนี้ใช้หน่วยความจำมากกว่าคีย์ธรรมดาที่มีเวลาหมดอายุ
VasileM

3

มีเฟรมเวิร์กRedisson java ซึ่งใช้แฮชMapอ็อบเจ็กต์ด้วยการรองรับ TTL รายการ มันใช้hmapและzsetRedis วัตถุภายใต้ประทุน ตัวอย่างการใช้งาน:

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

แนวทางนี้มีประโยชน์มากทีเดียว


แต่คุณจะสร้างแผนที่ได้อย่างไร? เพราะฉันไม่พบบทช่วยสอนหรือวิธีการสร้าง / ตั้งค่าใด ๆ
FaNaT

@ ZoltánNémethในแผนที่ Redis สร้างขึ้นโดยอัตโนมัติเมื่อใส่ค่าแรก
Nikita Koksharov

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)ในการโทรครั้งเดียว
doublesharp

const keys = Object.keys(reply).filter(key => reply[key] && JSON.parse(reply[key]).expiryTime < Date.now()); client.hdel(HASH_NAME, ...keys);
doublesharp

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

25
ฉันไม่คิดว่าเขาต้องการให้คีย์ทั้งหมดในแฮชหมดอายุแต่คีย์ทั้งหมดในแฮชซึ่งเก่ากว่า 1 เดือนมีเพียงบางคีย์เท่านั้น AFAIK ใดที่เป็นไปไม่ได้
UpTheCreek

1
IMHO คำถามให้เราสมมตินี้ ดังนั้นโจนาธานจึงได้รับ +1 จากฉันเพราะเขาช่วยฉัน! Thanx!
longliveenduro

"f1" และ "f2" หมดอายุได้อย่างไร
vgoklani

4
สิ่งนี้ไม่ได้ตอบคำถามหรือช่วยเลย ความต้องการคือการหมดอายุองค์ประกอบในแฮไม่ใช่แฮชเอง
รอน

@UpTheCreek ขอบคุณ!
Jonathan Kim

1

คุณสามารถจัดเก็บคีย์ / ค่าใน Redis แตกต่างกันเพื่อให้บรรลุเป้าหมายนี้โดยเพียงแค่เพิ่มคำนำหน้าหรือเนมสเปซให้กับคีย์ของคุณเมื่อคุณจัดเก็บคีย์เหล่านั้นเช่น "hset_"

  • รับคีย์ / ค่าGET hset_keyเท่ากับHGET hset key

  • เพิ่มคีย์ / ค่าSET hset_key valueเท่ากับHSET hset key

  • รับคีย์ทั้งหมดKEYS hset_*เท่ากับHGETALL hset

  • รับ vals ทั้งหมดควรทำใน 2 ops ก่อนอื่นให้รับคีย์ทั้งหมดKEYS hset_*จากนั้นรับค่าสำหรับแต่ละคีย์

  • เพิ่มคีย์ / ค่าด้วยTTL หรือหมดอายุซึ่งเป็นหัวข้อคำถาม:

 SET hset_key value
 EXPIRE hset_key

หมายเหตุ : KEYSจะค้นหาคีย์ที่ตรงกันในฐานข้อมูลทั้งหมดซึ่งอาจส่งผลต่อประสิทธิภาพโดยเฉพาะอย่างยิ่งหากคุณมีฐานข้อมูลขนาดใหญ่

บันทึก:

  • KEYSจะค้นหาคีย์ในฐานข้อมูลทั้งหมดซึ่งอาจส่งผลต่อประสิทธิภาพโดยเฉพาะอย่างยิ่งหากคุณมีฐานข้อมูลขนาดใหญ่ ในขณะที่SCAN 0 MATCH hset_*อาจจะดีกว่าตราบเท่าที่ไม่ได้ปิดกั้นเซิร์ฟเวอร์ แต่ประสิทธิภาพยังคงเป็นปัญหาในกรณีของฐานข้อมูลขนาดใหญ่

  • คุณอาจสร้างฐานข้อมูลใหม่เพื่อจัดเก็บคีย์เหล่านี้แยกกันซึ่งคุณต้องการให้หมดอายุโดยเฉพาะหากเป็นคีย์ชุดเล็ก

ขอบคุณ @DanFarrell ที่ให้ความสำคัญกับปัญหาด้านประสิทธิภาพที่เกี่ยวข้องกับ KEYS


2
โปรดทราบว่านี่เป็นการเปลี่ยนแปลงที่สำคัญของลักษณะการทำงาน
Daniel Farrell

ยังไง! หากคุณพูดถึงความซับซ้อนของเวลาการดำเนินการทั้งหมดนี้มีความซับซ้อนของเวลาเช่นเดียวกับhashset.. รับ O (1) ตั้ง O (1) รับ O (n) ทั้งหมด
มูฮัมหมัดโซลิมาน

"พิจารณา KEYS เป็นคำสั่งที่ควรใช้ในสภาพแวดล้อมการใช้งานจริงด้วยความระมัดระวังเป็นอย่างยิ่ง" redis.io/commands/KEYS HGETALL เป็นO(n)จำนวนของสิ่งต่างๆในชุดKEYSไปจนถึงจำนวนสิ่งต่างๆในฐานข้อมูล
Daniel Farrell

นั่นเป็นความจริงscan 0 match namespace:*อาจจะดีกว่าตราบเท่าที่ไม่ได้ปิดกั้นเซิร์ฟเวอร์
Muhammad Soliman

1
นอกจากนี้ให้แยกคีย์เหล่านี้หากเป็นชุดเล็กไปยังฐานข้อมูลอื่น ขอบคุณ @DanFarrell
Muhammad Soliman

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

คุณสามารถใช้Sorted Setใน 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)

นี่จะทำให้คีย์ลูกทั้งหมดในhash 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)

7
คำถามที่เป็นเรื่องเกี่ยวกับวันหมดอายุของเด็กไม่เต็มรูปแบบhset hset
thangdc94

ไม่ตอบคำถามที่ถาม
peteclark3
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.