Làm thế nào để "HẾT HẠN" khóa con "HSET" trong redis?


107

Tôi cần hết hạn tất cả các khóa trong redis hash, cũ hơn 1 tháng.

Câu trả lời:


117

Điều này là không thể , vì mục đích giữ cho Redis đơn giản .

Quoth Antirez, người tạo ra Redis:

Xin chào, bạn không thể sử dụng khóa cấp cao nhất khác cho trường cụ thể đó hoặc lưu trữ cùng với trường đã nộp một trường khác có thời gian hết hạn, tìm nạp cả hai và cho ứng dụng hiểu liệu nó có còn hợp lệ hay không dựa trên thời điểm hiện tại.


8
đây là lý do tại sao redis là một phần mềm tuyệt vời như vậy. họ biết nơi để giữ cho nó đơn giản
tObi

20

Redis không hỗ trợ việc TTLsử dụng các hàm băm khác với khóa trên cùng, điều này sẽ làm hết hạn toàn bộ hàm băm. Nếu bạn đang sử dụng một cụm phân đoạn, có một cách tiếp cận khác mà bạn có thể sử dụng. Cách tiếp cận này không thể hữu ích trong tất cả các tình huống và các đặc điểm hoạt động có thể khác với các đặc điểm dự kiến. Vẫn đáng nói:

Khi có một hàm băm, cấu trúc về cơ bản giống như sau:

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

Vì chúng ta muốn thêm TTLvào các phím con, chúng ta có thể di chuyển chúng lên các phím trên cùng. Điểm chính là khóa bây giờ phải là sự kết hợp của hash_top_keyvà khóa con:

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

Chúng tôi đang sử dụng {}ký hiệu có mục đích. Điều này cho phép tất cả các phím đó rơi vào cùng một chỗ hash slot. Bạn có thể đọc thêm về nó ở đây: https://redis.io/topics/cluster-tutorial

Bây giờ nếu chúng ta muốn thực hiện thao tác băm tương tự, chúng ta có thể làm:

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

Điều thú vị ở đây là HGETALL. Đầu tiên, chúng tôi nhận được hash slotcho tất cả các chìa khóa con của chúng tôi. Sau đó, chúng tôi nhận được các khóa cho cụ thể đó hash slotvà cuối cùng chúng tôi truy xuất các giá trị. Chúng ta cần phải cẩn thận ở đây vì có thể có nhiều hơn nchìa khóa cho điều đó hash slotvà cũng có thể có những chìa khóa mà chúng ta không quan tâm đến nhưng chúng đều giống nhau hash slot. Chúng tôi thực sự có thể viết một Luatập lệnh để thực hiện các bước đó trong máy chủ bằng cách thực thi một lệnh EVALhoặc EVALSHA. Một lần nữa, bạn cần phải xem xét hiệu suất của phương pháp này đối với tình huống cụ thể của bạn.

Một số tài liệu tham khảo thêm:


Cách tiếp cận này sử dụng nhiều bộ nhớ hơn các khóa đơn giản với thời gian hết hạn.
VasileM

3

Có một khuôn khổ java Redisson triển khai Mapđối tượng băm với hỗ trợ TTL mục nhập. Nó sử dụng hmapzsetRedis các đối tượng dưới mui xe. Ví dụ sử dụng:

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

Cách làm này khá hữu ích.


nhưng làm thế nào bạn có thể tạo một bản đồ? bởi vì tôi không tìm thấy bất kỳ hướng dẫn hay một tạo / bộ phương pháp
FaNaT

@ ZoltánNémeth Trong bản đồ Redis được tạo tự động khi giá trị đầu tiên được chèn vào.
Nikita Koksharov,

3

Điều này có thể xảy ra trong KeyDB , một Fork of Redis. Bởi vì nó là một Fork hoàn toàn tương thích với Redis và hoạt động như một sự thay thế.

Chỉ cần sử dụng lệnh EXPIREMEMBER. Nó hoạt động với các tập hợp, băm và các tập hợp được sắp xếp.

Khóa con của tên khóa EXPIREMEMBER [time]

Bạn cũng có thể sử dụng TTL và PTTL để xem ngày hết hạn

Khóa con tên khóa TTL

Tài liệu khác có sẵn tại đây: https://docs.keydb.dev/docs/commands/#expiremember


2

Về việc triển khai NodeJS, tôi đã thêm expiryTimetrường tùy chỉnh trong đối tượng mà tôi lưu trong HASH. Sau đó, sau một khoảng thời gian cụ thể, tôi xóa các mục HASH đã hết hạn bằng cách sử dụng mã sau:

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);
            }
        })
    }
});

Bạn có thể làm cho điều này hiệu quả hơn bằng cách sử dụng Array.filterđể tạo một mảng keysđể xóa khỏi hàm băm sau đó chuyển nó đến client.hdel(HASH_NAME, ...keys)trong một lệnh gọi.
doublesharp

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

1

Bạn có thể. Đây là một ví dụ.

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

Sử dụng lệnh EXPIRE hoặc EXPIREAT .

Nếu bạn muốn hết hạn các khóa cụ thể trong hàm băm cũ hơn thì 1 tháng. Điều này là không thể. Lệnh hết hạn Redis dành cho tất cả các khóa trong hàm băm. Nếu bạn đặt khóa băm hàng ngày, bạn có thể đặt thời gian tồn tại của khóa.

hset key-20140325 f1 1
expire key-20140325 100
hset key-20140325 f1 2

24
Tôi không nghĩ anh ấy muốn hết hạn tất cả các khóa trong băm, thay vì tất cả các khóa trong băm cũ hơn 1 tháng , vì vậy chỉ một số trong số chúng. AFAIK nào không được.
UpTheCreek,

1
IMHO câu hỏi hãy để chúng tôi giả định điều này. Vì vậy, Jonathan nhận được +1 từ tôi, vì anh ấy đã giúp tôi! Thanx!
longliveenduro

làm thế nào để bạn hết hạn "f1" và "f2"?
vgoklani

4
Điều này không trả lời câu hỏi hoặc giúp ích gì cả. Sự cần thiết là làm hết hạn các phần tử trong hàm băm, không phải bản thân hàm băm.
Ron

@UpTheCreek Cảm ơn bạn!
Jonathan Kim

1

Bạn có thể lưu trữ khóa / giá trị trong Redis theo cách khác để đạt được điều này, bằng cách thêm tiền tố hoặc không gian tên vào các khóa của bạn khi bạn lưu trữ chúng, ví dụ: "hset_"

  • Nhận một khóa / giá trị GET hset_keybằngHGET hset key

  • Thêm khóa / giá trị SET hset_key valuebằngHSET hset key

  • Nhận tất cả các khóa KEYS hset_*bằng vớiHGETALL hset

  • Nhận tất cả các vals nên được thực hiện trong 2 hoạt động, trước tiên lấy tất cả các khóa KEYS hset_*sau đó lấy giá trị cho mỗi khóa

  • Thêm khóa / giá trị bằng TTL hoặc hết hạn là chủ đề của câu hỏi:

 SET hset_key value
 EXPIRE hset_key

Lưu ý : KEYSsẽ tra cứu khóa khớp với toàn bộ cơ sở dữ liệu có thể ảnh hưởng đến hiệu suất, đặc biệt nếu bạn có cơ sở dữ liệu lớn.

Ghi chú:

  • KEYSsẽ tra cứu để khớp khóa trong toàn bộ cơ sở dữ liệu, điều này có thể ảnh hưởng đến hiệu suất, đặc biệt nếu bạn có cơ sở dữ liệu lớn. mặc dù SCAN 0 MATCH hset_*có thể tốt hơn miễn là nó không chặn máy chủ nhưng hiệu suất vẫn là một vấn đề trong trường hợp cơ sở dữ liệu lớn.

  • Bạn có thể tạo một cơ sở dữ liệu mới để lưu trữ riêng các khóa này mà bạn muốn hết hạn, đặc biệt nếu chúng là một nhóm khóa nhỏ.

Cảm ơn @DanFarrell, người đã nêu bật vấn đề hiệu suất liên quan đến KEYS


1
chỉ cần lưu ý đây là một sự thay đổi đáng kể đối với đặc tính hiệu suất
Daniel Farrell

làm sao! nếu bạn nói về sự phức tạp thời gian, tất cả các hoạt động này có độ phức tạp thời gian tương tự như hashset.. get O (1) bộ O (1) nhận được tất cả O (n)
Muhammad Soliman

"coi KEYS là một lệnh chỉ nên được sử dụng trong môi trường sản xuất hết sức cẩn thận." redis.io/commands/KEYS . HGETALL là O(n)số thứ trong tập hợp, KEYSlà số thứ trong DB.
Daniel Farrell,

đó là sự thật, scan 0 match namespace:*có thể là tốt hơn miễn là nó không chặn máy chủ
Muhammad Soliman

1
ngoài ra, hãy tách các khóa này, nếu chúng được đặt nhỏ, thành cơ sở dữ liệu khác nhau. cảm ơn @DanFarrell
Muhammad Soliman

1

Chúng tôi đã có cùng một vấn đề được thảo luận ở đây.

Chúng tôi có hàm băm Redis, một khóa cho các mục nhập băm (cặp tên / giá trị) và chúng tôi cần giữ thời gian hết hạn riêng lẻ trên mỗi mục nhập băm.

Chúng tôi đã triển khai điều này bằng cách thêm n byte dữ liệu tiền tố chứa thông tin hết hạn được mã hóa khi chúng tôi viết giá trị mục nhập băm, chúng tôi cũng đặt khóa hết hạn tại thời điểm có trong giá trị được ghi.

Sau đó, khi đọc, chúng tôi giải mã tiền tố và kiểm tra xem có hết hạn hay không. Đây là chi phí bổ sung, tuy nhiên, các lần đọc vẫn là O (n) và toàn bộ khóa sẽ hết hạn khi mục nhập băm cuối cùng đã hết hạn.


0

Bạn có thể sử dụng Redis Keyspace Notifications bằng cách sử dụng psubscribe"__keyevent@<DB-INDEX>__:expired".

Cùng với đó, mỗi khi khóa đó hết hạn, bạn sẽ nhận được thông báo được xuất bản trên kết nối redis của mình.

Về câu hỏi của bạn về cơ bản, bạn tạo một khóa "bình thường" tạm thời bằng cách sử dụng setvới thời gian hết hạn tính bằng s / ms. Nó phải khớp với tên của khóa mà bạn muốn xóa trong tập hợp của mình.

Vì khóa tạm thời của bạn sẽ được xuất bản lên kết nối redis của bạn, hãy giữ "__keyevent@0__:expired" khi nó hết hạn, bạn có thể dễ dàng xóa khóa khỏi bộ ban đầu vì thông báo sẽ có tên của khóa.

Một ví dụ đơn giản trong thực tế trên trang đó: https://medium.com/@micah1powell/using-redis-keyspace-notifications-for-a-reminder-service-with-node-c05047befec3

doc: https://redis.io/topics/notifications (tìm cờ xE)


0

Bạn có thể sử dụng Sorted Set in redis để có được vùng chứa TTL với dấu thời gian là điểm số. Ví dụ: bất cứ khi nào bạn chèn một chuỗi sự kiện vào tập hợp, bạn có thể đặt điểm của nó thành thời gian sự kiện. Vì vậy, bạn có thể nhận dữ liệu của bất kỳ khoảng thời gian nào bằng cách gọi zrangebyscore "your set name" min-time max-time

Hơn nữa, chúng tôi có thể làm hết hạn bằng cách sử dụng zremrangebyscore "your set name" min-time max-timeđể xóa các sự kiện cũ.

Hạn chế duy nhất ở đây là bạn phải làm công việc quản lý nhà từ một quy trình bên ngoài để duy trì kích thước của bộ.


-1

Bạn có thể hết hạn băm Redis một cách dễ dàng, chẳng hạn như sử dụng python

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

Điều này sẽ hết hạn tất cả các khóa con trong hash hashed_user sau 10 giây

giống từ 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"

sau 10 giây

127.0.0.1:6379> hgetall testt
(empty list or set)

6
câu hỏi là về hsetcon hết hạn không phải là đầy đủ hset.
thangdc94

không trả lời câu hỏi được hỏi
peteclark 3
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.