redis发布订阅功能
一.背景
目前做了一个功能,需要抓取到登陆时session自动失效的时间,于是在同事的建议下第一次去使用redis的发布订阅功能,这其中踩了些坑,还是耗费了几天时间才做出来了。
发布订阅功能要求reids最少要是2.8版本以上,大概功能就是发布者发布消息,订阅者接收到发布者发布的消息,具体概念功能,网上可以看哈,这里不多赘述。
二.本地环境
1.部署环境:docker集成的ngnix,mysql,php,redis 环境
2.编程语言:php
3.框架:TP5
4.数据库:mysql,redis
三.步骤
1.订阅redis的过期失效事件,只要redis中有键过期则通知订阅的客户端,有两种方式配置:
第一种是文件配置:修改reids配置文件(redis.conf)【window系统配置文件为:redis.windows.conf 】,更改 notify-keyspace-events "" 为 notify-keyspace-events "Ex",然后重启redis服务。
第二种是命令行配置: config set notify-keyspace-events KEA
坑一:在windosw上用文件配置发现不能生效,只有命令行配置生效了,这个在本人电脑上出现了这个情况
2.自定义失效的键/自定义发布
代码:
$redis->setex($key,3,'redis延迟任务'); //$key 3秒钟失效,失效时通知订阅方,自动发布
如果有需要自己发布的需求,不需要失效的,如下:
$res=$redis->publish('test','hello,world'.rand(00000,99999)); // test为发布的频道名称,hello,world为发布的消息
这里我的需求是session失效,session用的是在tp中配置,tp框架可将session写在redis中而不是文件的形式,而且可配置有效时间,所以我不需 要配置上述命令,tp框架已经帮我搞定了。
3.订阅者逻辑处理
代码:
//$msg为失效键的键名
function keyCallback($redis, $pattern, $channel, $msg)
{
//回调函数里就是失效时,通知的地方,这里写redis键失效后的处理,$msg为失效键的键名
}
上述代码是原生php代码中的逻辑,这里讲下我在tp中的处理,因为TP是对定时任务做了封装,可以自定义命令行,不过多赘述, https://www.kancloud.cn/manual/thinkphp5/235129,如果没用过的同学可以看哈
tp5框架中的代码
<?php
namespace app\home\command;use think\console\Command;
use think\console\Input;use think\console\Output;
class Testextends Command
{
protected functioncon figure()
{
$this->setName('test')->setDescription('Here is the remark ');
}
protected function execute(Input $input,Output $output)
{
`````
//订阅者的回调函数
$s->psubscribe(array('__keyevent@0__:expired'), function ($redis, $pattern, $channel , $msg){
//回调函数里就是失效时,通知的地方,这里写redis键失效后的处理,$msg为失效键的键名
```````
}
}
}
坑二:订阅的回调函数里,对redis的任何操作都将无效,任何的增删改查都无法用,官方语言:消息订阅者,即subscribe客户端,需要独占链接,即进行subscribe期间,redis-client无法穿插其他操作,此时client以阻塞的方式等待“publish端”的消息;这一点很好理解,因此subscribe端需要使用单独的链接,甚至需要在额外的线程中使用。
4.订阅过后,因为我们需要时刻知道是否有失效事件的产生,所以这个时候我们需要在服务器上一直挂起这个任务
我在这里用的是nohup,关于这个linux命令我介绍几个主要的:
第一步,不是命令,是在你要执行的脚本文件第一行的位置上声明php编译器的路径
#! /usr/bin/env php
注:这里我踩了一坑,我照这样配置发现不生效,我用的是ngnix环境,后面问同事,发现ngnix并不会像apache有php.exe文件,ngnix上是php环境目录,因此,我的声明最后改成了如下
#! /usr/bin/env/php
第二步,才是在服务器配置
a. 配置需要后台挂起执行的命令:
nohup 命令 &
注:这里也是我踩的一坑,网上给出的都是 nobup 文件 &,但是我们是用框架,而不是原生php,再加上本地是在docker中搭建的环境,我这里最终的配置是:
nohup docker exec php-fpm容器名 php编译器位置 tp框架think目录 任务命令名 &
b.查看后台运行的进程:
这里遇到了一个小坑,网上很多资料说的是用 jobs -l,但是有个弊端,这个命令只对当前终端生效的,关闭终端后,在另一个终端jobs已经无法看到后台跑得程序了,其实进程已经有了,因为jobs命令是列出的当前shell环境已启动的作业状态,所以一旦关闭终端就没得了,推荐用 ps aux 来查看进程,这个最准确的去判断当前系统的所有进程
c.终止后台运行的进程:
kill -9 进程号