一.需求
在redis中,設置好key和生存時間之后,希望key過期被刪除時能夠及時的發送一個通知告訴我key,以便我做后續的一些操作.
二.環境
系統:windows10 php:7.1 redis:3.2
三.redis
redis2.8.0版本之后推出了鍵空間通知,如何使用呢?當redis的key被刪除時,redis會發送兩種不同類型的事件,特定的事件會往特定的頻道發送通知,我們只要訂閱這個特定的頻道等待通知即可.
兩種事件通知:
PUBLISH __keyspace@0__:mykey del
PUBLISH __keyevent@0__:del mykey
以keyspace為前綴的頻道被稱為鍵空間通知(key-space notification),訂閱這個頻道 __keyspace@0__:mykey,可以接收0號數據庫中所有修改鍵 mykey 的事件,訂閱者將接收到被執行的事件的名字,就是 del;
而以keyevent為前綴的頻道則稱為鍵事件通知(key-event notification),訂閱這個頻道 __keyevent@0__:del,則可以接收0號數據庫中所有執行 del 命令的鍵,訂閱者將接收到被執行事件的鍵的名字,就是 mykey
我需要獲取key 的名字,所以需要訂閱__keyevent@0__:頻道.
四.實現步驟
(1) 打開redis配置文件redis.conf,找到notify-keyspace-events 將其設為Ex,E代表鍵事件通知,x代表過期事件,每當有過期鍵被刪除時發送,然后重啟redis使配置生效;
(2) 創建demo.php文件:
1 <?php 2 3 class RedisInstance 4 { 5 private $redis; 6 7 public function __construct($host = '127.0.0.1', $port = 6379) 8 { 9 $this->redis = new Redis(); 10 $this->redis->connect($host, $port); 11 } 12 13 public function expire($key = null, $time = 0) 14 { 15 return $this->redis->expire($key, $time); 16 } 17 18 public function psubscribe($patterns = array(), $callback) 19 { 20 $this->redis->psubscribe($patterns, $callback); 21 } 22 23 public function setOption() 24 { 25 $this->redis->setOption(\Redis::OPT_READ_TIMEOUT,-1); 26 } 27 28 } 29 30 echo "程序開始執行..\n"; 31 $redis = new RedisInstance(); 32 $redis->setOption(); 33 $redis->psubscribe(array('__keyevent@0__:expired'), 'callback'); 34 //回調 35 function callback($redis, $pattern, $chan, $msg) 36 { 37 echo "$pattern\n"; 38 echo "$chan\n"; 39 echo "$msg\n"; 40 /*業務邏輯*/ 41 }
(3) 使用php運行demo.php文件,首先你的php是否設置環境變量,設置方法:找到我的電腦右鍵選擇屬性—高級系統設置—環境變量—找到path變量編輯/沒有path變量的可以新建一個—將你的php.exe的絕對路徑放進去保存即可,之后就可以直接使用php命令了,其次必須開啟了redis拓展,查看是否裝有redis拓展:
php -m
確認已安裝拓展,直接運行文件:
php demo.php

(4) 打開一個redis客戶端,即運行redis-cli.exe文件或者使用命令 redis-cli.exe -p 6379,創建一個key,並將過期時間設置在五秒,然后觀察運行demo.php的窗口:

五秒之后key過期被刪除,php接收通知走進回調方法,這里就可以處理業務邏輯了.
五.測試通知時效性:
寫一個腳本循環往redis中插入50條記錄,且每條記錄的過期時間在五秒和十秒隨機產生,觀察接收到的通知狀態:

注意:redis 使用以下兩種方式刪除過期的鍵:
- 當一個鍵被訪問時,程序會對這個鍵進行檢查,如果鍵已經過期,那么該鍵將被刪除。
- 底層系統會在后台漸進地查找並刪除那些過期的鍵,從而處理那些已經過期但是不會被訪問到的鍵。
也就是說如果一個鍵過期了但是沒有程序訪問它,並且底層系統還沒有排查到它的時候這個鍵是不會被刪除的,也不會有通知產生,因此,redis 產生 expired 通知的時間為過期鍵被刪除的時候, 而不是鍵的生存時間變為 0 的時候。
