Câu trả lời:
Đ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.
Redis không hỗ trợ việc TTL
sử 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 TTL
và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_key
và 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 slot
cho 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 slot
và 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 n
chìa khóa cho điều đó hash slot
và 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 Lua
tậ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 EVAL
hoặ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ó 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 hmap
và zset
Redis 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.
Đ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
Về việc triển khai NodeJS, tôi đã thêm expiryTime
trườ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);
}
})
}
});
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.
const keys = Object.keys(reply).filter(key => reply[key] && JSON.parse(reply[key]).expiryTime < Date.now()); client.hdel(HASH_NAME, ...keys);
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
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_key
bằngHGET hset key
Thêm khóa / giá trị SET hset_key value
bằ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 ý : KEYS
sẽ 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ú:
KEYS
sẽ 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
hashset
.. get O (1) bộ O (1) nhận được tất cả O (n)
O(n)
số thứ trong tập hợp, KEYS
là số thứ trong DB.
scan 0 match namespace:*
có thể là tốt hơn miễn là nó không chặn máy chủ
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.
Bạn có thể sử dụng Redis Keyspace Notifications bằng cách sử dụng psubscribe
và "__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 set
vớ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)
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ộ.
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)
hset
con hết hạn không phải là đầy đủ hset
.