《Redis的鍵空間通知詳解》要點:
本文介紹了Redis的鍵空間通知詳解,希望對您有用。如果有疑問,可以聯系我們。
重要: 鍵空間通知(Keyspace Notification)是一個從Redis 2.8.0版本開始可用的功能.
一、功能概述
鍵空間通知使得客戶端能夠訂閱Pub/Sub(發布/訂閱)頻道,這樣客戶端便能接收到以某種方式影響Redis數據集的事件.
可能接收到的事件示例,如下所示:
所有影響到一個給定鍵的命令.
所有接收到一個LPUSH命令的鍵.
所有數據庫-0中的鍵全都過期.
Redis會使用標準的Pub/Sub層來傳遞事件,因此,實現了Pub/Sub功能的客戶端能夠直接使用這個功能,而不用進行任何修改.
因為Redis的Pub/Sub功能當前是“觸發后不管(Fire and Forget)”的,所以如果你的應用程序對事件有著可靠通知的要求,那么它就不能使用Redis的鍵空間通知功能.也便是說,如果你的Pub/Sub客戶端斷開連接,然后再重新連接,那么在客戶端斷開連接的期間內傳遞的所有事件都會丟失.
Redis將來會改善事件傳遞的可靠性,但是很有可能會以一種更加常規的方式來辦理這個問題,有可能會提高Pub/Sub功能自身的可靠性,也有可能會通過Lua腳本攔截Pub/Sub消息,然后再執行某些操作(例如,將事件存入一個列表之中).
二、事件類型
每次執行會影響到Redis數據空間的操作時,鍵空間通知就會發送兩個不同類型的事件.以DEL操作為例,當刪除數據庫-0
中的一個名為mykey
的鍵時,將會觸發Redis傳遞兩條消息,完全等價于下面兩條PUBLISH命令:
PUBLISH __keyspace@0__:mykey del
PUBLISH __keyevent@0__:del mykey
很容易看出,如何讓一個頻道能夠監聽mykey
鍵相關的所有事件,以及如何讓另一個頻道能夠獲取del
操作所影響的所有的鍵的有關信息.
第一種類型的事件,頻道名稱的前綴為keyspace
,這種事件被稱為鍵空間通知;而第二種類型的事件,頻道名稱的前綴為keyevent
,這種事件被稱為鍵事件通知.
在上面的示例中,Redis會針對mykey
鍵產生一個del
事件.期間發生的事情,如下所示:
鍵空間頻道會接收到一條消息,它的內容是事件名稱.
鍵事件頻道會接收到一條消息,它的內容是鍵的名稱.
為了使Redis只傳遞我們感興趣的事件子集,因此只可以使用一種類型的通知.
三、配置辦法
在默認情況下,鍵空間的事件通知功能是禁用的,因為這個功能會消耗一些CPU性能,雖然幾乎感覺不到性能消耗.有兩種辦法可以啟用通知功能:修改redis.conf文件的notify-keyspace-events
參數,或者使用CONFIG SET命令.
將上述參數設置為空字符串,就能禁用通知功能.如果想要啟用這個功能,那么就要將上述參數設置為一個空字符串,這個字符串由多個字符組成,其中的每個字符都具有特殊含義,如下表所示:
字符 | 含義 |
---|---|
K | 鍵空間(Keyspace)事件,通過__keyspace@<db>__ 前綴的頻道發布. |
E | 鍵事件(Keyevent)事件,通過__keyevent@<db>__ 前綴的頻道發布. |
g | 通用的命令(不特定類型),例如:DEL、EXPIRE、RENAME,等等. |
$ | 字符串(String)相關的命令. |
l | 列表(List)相關的命令. |
s | 集合(Set)相關的命令. |
h | 哈希(Hash)相關的命令. |
z | 有序集合相關的命令. |
x | 過期事件(每當一個鍵過期時,便會產生這種事件). |
e | 內存回收事件(當達到最大內存,然后回收某個鍵的內存時,便會產生這種事件). |
A | g$lshzxe的別名.因此,“AKE”字符串可以表示所有的事件. |
配置字符串至少應當包括K
或E
字符.否則,即使這個字符串包括其他任何字符,Redis也不會傳遞任何事件.
例如,若只想針對列表(List)啟用鍵空間事件,則配置參數必需設置為Kl
,以此類推.
KEA
字符串可用于啟用每種可能的事件.
四、不同命令產生的事件
不同的命令會產生不同類型的事件,如以下列表所示:
DEL
這個命令會為每個被刪除的鍵產生一個del
事件.
RENAME
這個命令會產生兩個事件,一個為原始鍵產生的rename_from
事件,以及一個為目標鍵產生的rename_to
事件.
EXPIRE
當為某個鍵設置過期時間時,這個命令便會產生一個expire
事件;或者,每當為某個待刪除的鍵設置一個過期結果時,這個命令便會產生一個expired
事件(請參考EXPIRE命令的相關文檔).
SORT
當使用STORE
選項來設置一個新鍵時,這個命令便會產生一個sortstore
事件.如果結果列表為空,并且使用了STORE
選項,并且已經存在一個同名的鍵,那么Redis便會刪除這個已有的鍵,在這種情況下,這個命令還會產生一個del
事件.
SET
這個命令,以及它的所有變種(SETEX、SETNX、GETSET)命令,都會產生set
事件.除此之外,SETEX命令還會產生一個expire
事件.
MSET
這個命令會為每個鍵單獨產生一個set
事件.
SETRANGE
這個命令會產生一個setrange
事件.
INCR、DECR、INCRBY、DECRBY
這些命令都會產生incrby
事件.
INCRBYFLOAT
這個命令會產生一個incrbyfloat
事件.
APPEND
這個命令會產生一個append
事件.
LPUSH、LPUSHX
這些命令都會產生一個lpush
事件,即使有多個輸入元素時,也是如此.
RPUSH、RPUSHX
這些命令都會產生一個rpush
事件,即使有多個輸入元素時,也是如此.
RPOP
這個命令會產生一個rpop
事件.另外,如果從列表中彈出最后一個元素,那么這個列表對應的鍵就會被刪除,此時還會產生一個del
事件.
LPOP
這個命令會產生一個lpop
事件.另外,如果從列表中彈出最后一個元素,那么這個列表對應的鍵就會被刪除,此時還會產生一個del
事件.
LINSERT
這個命令會產生一個linsert
事件.
LSET
這個命令會產生一個lset
事件.
LREM
這個命令會產生一個lrem
事件.另外,如果運行這個命令之后,列表變為空表,那么便會刪除這個列表對應的鍵,此時還會產生一個del
事件.
LTRIM
這個命令會產生一個ltrim
事件.另外,如果運行這個命令之后,列表變為空表,那么便會刪除這個列表對應的鍵,此時還會產生一個del
事件.
RPOPLPUSH、BRPOPLPUSH
這兩個命令都會產生一個rpop
事件和lpush
事件.這兩個事件的產生順序都是固定不變的,先產生rpop
事件,然后再產生lpush
事件.另外,如果運行這兩個命令之后,列表變為空表,那么便會刪除這個列表對應的鍵,此時還會產生一個del
事件.
HSET、HSETNX、HMSET
這些命令都會產生一個hset
事件.
HINCRBY
這個命令會產生一個hincrby
事件.
HINCRBYFLOAT
這個命令會產生一個hincrbyfloat
事件.
HDEL
這個命令會產生一個hdel
事件.如果運行這個命令之后,哈希變為空,那么便會刪除這個哈希對應的鍵,此時還會產生一個del
事件.
SADD
這個命令會產生一個sadd
事件,即使有多個輸入元素時,也是如此.
SREM
這個命令會產生一個srem
事件.如果運行這個命令之后,集合變為空,那么便會刪除這個集合對應的鍵,此時還會產生一個del
事件.
SMOVE
這個命令會為原始鍵產生一個srem
事件,然后為目標鍵產生一個sadd
事件.
SPOP
這個命令會產生一個spop
事件.如果運行這個命令之后,集合變為空,那么便會刪除這個集合對應的鍵,此時還會產生一個del
事件.
SINTERSTORE、SUNIONSTORE、SDIFFSTORE
這些命令會分別產生sinterstore
、sunionostore
和sdiffstore
事件.在特殊情況下,如果運行這些命令得到的集合為空,并且用于存儲結果的鍵已經存在,那么這個鍵將會被刪除,然后還會產生一個del
事件.
ZINCRBY
這個命令會產生一個zincr
事件.
ZADD
這個命令會產生一個zadd
事件,即使有多個輸入元素時,也是如此.
ZREM
這個命令會產生一個zrem
事件,即使必要刪除多個元素時,也是如此.如果運行這個命令之后,有序集合變為空,那么便會刪除這個有序集合對應的鍵,此時還會產生一個del
事件.
ZREMRANGEBYSCORE
這個命令會產生一個zrembyscore
事件.如果運行這個命令之后,有序集合變為空,那么便會刪除這個有序集合對應的鍵,此時還會產生一個del
事件.
ZREMRANGEBYRANK
這個命令會產生一個zrembyrank
事件.如果運行這個命令之后,有序集合變為空,那么便會刪除這個有序集合對應的鍵,此時還會產生一個del
事件.
ZINTERSTORE、ZUNIONSTORE
這兩個命令會分別產生zinterstore
和zunionstore
事件.在特殊情況下,如果運行這些命令得到的有序集合為空,并且用于存儲結果的鍵已經存在,那么這個鍵將會被刪除,然后還會產生一個del
事件.
每當一個鍵因為過期而被刪除時,便會產生一個expired
事件.
每當一個鍵因為maxmemory
策略而被刪除,以便于回收內存時,便會產生一個evicted
事件.
重要: 所有的命令只有當目標鍵真的被修改時,才會產生事件.例如,當使用SREM命令刪除一個集合中并不存在的元素時,實際上沒有改變這個鍵的對應值,所以也就不會產生任何事件.
如果還在懷疑一個給定命令的事件是如何產生的,那么最簡單的辦法便是自己驗證一下.在Shell終端中運行以下命令:
redis-cli config set notify-keyspace-events KEA
redis-cli --csv psubscribe '__key*__:*'
此時,Redis客戶端便進入頻道監聽狀態,如下圖所示:
此時,在另一個Shell終端中使用redis-cli
命令向Redis服務器發送命令:
redis-cli set foo hello
然后,便能在前一個Shell終端中觀察到以下輸出信息:
五、過期事件的產生時機
Redis會通過以下兩種方式使得具有生存時間的鍵過期:
當使用某個命令拜訪這個鍵,然后發現這個鍵已經過期.
通過一個后臺系統在后臺漸進地查找已經過期的鍵,這樣還能夠收集從未被拜訪過的鍵.
當通過上述兩種方式之一拜訪某個鍵,并且發現這個鍵已經過期時,Redis就會產生expired
事件.結論便是,Redis服務器并不能保證每當鍵的生存時間降低至0的時候就能立刻產生expired
事件.
如果總是沒有任何命令拜訪這個已經過期的鍵,并且帶有生存時間(TTL:Time To Live)的鍵非常多的話,那么就很有可能感覺到鍵的生存時間降低至0和產生expired
事件之間具有明顯的延時.
基本上,只有當Redis服務器刪除已經過期的鍵時才會產生expired
事件,而不是當鍵的生存時間在理論上降低至0的時候.
六、鍵空間通知示例
接下來,會通過實際操作,簡單講解Redis鍵空間通知的使用辦法.
1. 安裝Redis
依照《在CentOS上安裝Redis緩存系統》安裝Redis服務器.
2. 啟用鍵空間通知功能
在Shell終端(此處取名為終端-1)中運行以下命令,進入Redis客戶端的命令行:
redis-cli
然后在終端-1的Redis客戶端的命令行中運行以下命令,啟用鍵空間通知功能的所有通知:
config set notify-keyspace-events KEA
3. 訂閱鍵空間通知和鍵事件通知
打開一個新的Shell終端(此處取名為終端-2),在其中運行以下命令,進入telnet命令行:
telnet localhost 6379
在終端-2的telnet命令行中,運行以下命令:
psubscribe __key*__:*
上述命令會訂閱鍵空間通知和鍵事件通知,當對某個鍵執行修改命令時,終端-2便會同時收到上述兩種通知.
4. 設置鍵的值
在終端-1的Redis客戶端的命令行中運行以下命令,設置一個鍵的值:
set mykey hello
5. 觀察結果
此時,便能在終端-2觀察到兩條通知消息,如下圖所示:
上圖的上半部分就是鍵空間通知,下半部分就是鍵事件通知.
《Redis的鍵空間通知詳解》是否對您有啟發,歡迎查看更多與《Redis的鍵空間通知詳解》相關教程,學精學透。維易PHP學院為您提供精彩教程。