redis对于键空间通知的介绍
一.redis过期删除策略:
在设置key的过期时间的时候,同时创建一个定时事件,当时间到达时,主动触发删除操作,这样做能尽可能快的保证删除key的实时性,但是在过期key相对比较多的时候,可能会占用一部分CPU
二.redis配置
找到redis配置文件,将其中notify-keyspace-events配置项修改为Ex
#Ex 意思为每当有键过期时发送通知
notify-keyspace-events Ex
修改完之后重启,可以开两个客户端进行测试
一个客户端设置过期键set timeoutkey 100 ex 3表示名为timeoutkey的这个键三秒后过期
另一个客户端订阅redis过期事件__keyevent@*__:expired 表示监听所有库的键过期事件
三.PHP代码实现
<?php
$redis = new Redis();
#链接redis
$redis->psubscribe(array('__keyevent@*__:expired'), function ($redis, $pattern, $chan, $msg){
var_dump($pattern);
var_dump($chan);
var_dump($msg);
});
打印:
string(22) "__keyevent@*__:expired"
string(22) "__keyevent@0__:expired"
string(10) "timeoutkey"
四:写在最后的bug(过期回调中无法再使用redis连接进行查询)
<?php
$redis = new Redis();
#链接redis
$key = $redis->get("demo");
var_dump($key);
$redis->psubscribe(array('__keyevent@*__:expired'), function ($redis, $pattern, $chan, $msg){
var_dump($pattern);
var_dump($chan);
var_dump($msg);
$key = $redis->get("demo");
var_dump($key);
});
代码示例
可以看到在闭包的打印中,无法查询到键为demo的变量,这里找到一句非官方解释:Redis 在发布订阅模式下,通常不支持向服务器发送非订阅相关的命令。如果需要再闭包中使用redis的话,可以通过开启一个子进程进行处理,参考这位大佬这样实现的https://blog.csdn.net/qq_24909089/article/details/125306349,这样可以实现在闭包内使用redis进行数据查询处理,但是如果数据过多的话每条数据都开启一个进程可能会带来资源的过度消耗,慎用
<?php
$redis = new Redis();
#连接redis
$redis->psubscribe(array('__keyevent@*__:expired'), function ($redis, $pattern, $chan, $msg){
$pid = pcntl_fork();
if ($pid == -1) {
die("could not fork\n");
}else if($pid>0){
$redis->close();
//这里不需要重新建立连接,get的时候会自动重连
$key = $redis->get("demo");
var_dump($key);
}
});