windows环境中的redis自动订阅

Redis介绍

   在 Redis 的 2.8.0 版本之后,其推出了一个新的特性——键空间消息(Redis Keyspace Notifications),它配合 2.0.0 版本之后的 SUBSCRIBE 就能完成这个定时任务的操作了,不过定时的单位是秒。

(1)Publish / Subscribe

 Redis 在 2.0.0 之后推出了 Pub / Sub 的指令,大致就是说一边给 Redis 的特定频道发送消息,另一边从 Redis 的特定频道取值——形成了一个简易的消息队列。

(2)Redis Keyspace Notifications

 在 Redis 里面有一些事件,比如键到期、键被删除等。然后我们可以通过配置一些东西来让 Redis 一旦触发这些事件的时候就往特定的 Channel 推一条消息。

 大致的流程就是我们给 Redis 的某一个 db 设置过期事件,使其键一旦过期就会往特定频道推消息,我在自己的客户端这边就一直消费这个频道就好了。

 以后一来一条定时任务,我们就把这个任务状态压缩成一个键,并且过期时间为距这个任务执行的时间差。那么当键一旦到期,就到了任务该执行的时间,Redis 自然会把过期消息推去,我们的客户端就能接收到了。这样一来就起到了定时任务的作用。

Key过期事件的Redis配置

1、这里需要配置 notify-keyspace-events 的参数为 “Ex”。x 代表了过期事件。notify-keyspace-events “Ex” 保存配置后,重启Redis服务,使配置生效。

2、安装Redis

PS D:\Redis> redis-server --service-install redis.windows.conf --loglevel verbose

结果:
[13592] 20 Jan 15:46:09.313 # Granting read/write access to 'NT AUTHORITY\NetworkService' on: "D:\Redis" "D:\Redis\"
[13592] 20 Jan 15:46:09.313 # Redis successfully installed as a service.

3、开启Redis

PS D:\Redis> redis-server --service-start

结果:
[14104] 20 Jan 15:46:52.139 # Redis service successfully started.

4、测试订阅是否成功

4.1 开启一个终端client01
在这里插入图片描述
4.2 开启另外一个终端client02
在这里插入图片描述
4.3 等过了10秒后,再看终端client01
在这里插入图片描述
说明:说明对过期Key信息的订阅是成功的。

PHP实现订阅代码

1、数据库操作类(db.class.php)

<?php

class mysql
{
    private $mysqli;
    private $result;
    /**
     * 数据库连接
     * @param $config 配置数组
     */

    public function connect()
    {
        $config=array(
            'host'=>'127.0.0.1',
            'username'=>'root',
            'password'=>'root',
            'database'=>'think',
            'port'=>3306,
        );

        $host = $config['host'];    //主机地址
        $username = $config['username'];//用户名
        $password = $config['password'];//密码
        $database = $config['database'];//数据库
        $port = $config['port'];    //端口号
        $this->mysqli = new mysqli($host, $username, $password, $database, $port);

    }
    /**
     * 数据查询
     * @param $table 数据表
     * @param null $field 字段
     * @param null $where 条件
     * @return mixed 查询结果数目
     */
    public function select($table, $field = null, $where = null)
    {
        $sql = "SELECT * FROM `{$table}`";
        //echo $sql;exit;
        if (!empty($field)) {
            $field = '`' . implode('`,`', $field) . '`';
            $sql = str_replace('*', $field, $sql);
        }
        if (!empty($where)) {
            $sql = $sql . ' WHERE ' . $where;
        }


        $this->result = $this->mysqli->query($sql);

        return $this->result;
    }
    /**
     * @return mixed 获取全部结果
     */
    public function fetchAll()
    {
        return $this->result->fetch_all(MYSQLI_ASSOC);
    }
    /**
     * 插入数据
     * @param $table 数据表
     * @param $data 数据数组
     * @return mixed 插入ID
     */
    public function insert($table, $data)
    {
        foreach ($data as $key => $value) {
            $data[$key] = $this->mysqli->real_escape_string($value);
        }
        $keys = '`' . implode('`,`', array_keys($data)) . '`';
        $values = '\'' . implode("','", array_values($data)) . '\'';
        $sql = "INSERT INTO `{$table}`( {$keys} )VALUES( {$values} )";
        $this->mysqli->query($sql);
        return $this->mysqli->insert_id;
    }
    /**
     * 更新数据
     * @param $table 数据表
     * @param $data 数据数组
     * @param $where 过滤条件
     * @return mixed 受影响记录
     */
    public function update($table, $data, $where)
    {
        foreach ($data as $key => $value) {
            $data[$key] = $this->mysqli->real_escape_string($value);
        }
        $sets = array();
        foreach ($data as $key => $value) {
            $kstr = '`' . $key . '`';
            $vstr = '\'' . $value . '\'';
            array_push($sets, $kstr . '=' . $vstr);
        }
        $kav = implode(',', $sets);
        $sql = "UPDATE `{$table}` SET {$kav} WHERE {$where}";

        $this->mysqli->query($sql);
        return $this->mysqli->affected_rows;
    }
    /**
     * 删除数据
     * @param $table 数据表
     * @param $where 过滤条件
     * @return mixed 受影响记录
     */
    public function delete($table, $where)
    {
        $sql = "DELETE FROM `{$table}` WHERE {$where}";
        $this->mysqli->query($sql);
        return $this->mysqli->affected_rows;
    }

    /**
     * 关闭数据库连接
     */
    public function close()
    {
        $this->mysqli->close();
    }
}

2、redis实例化类(redis2.class.php)

<?php

class Redis2
{
    private $redis;

    public function __construct($host = '127.0.0.1', $port = '6379',$password = '',$db = '15')
    {
        $this->redis = new Redis();
        $this->redis->connect($host, $port);    //连接Redis
        $this->redis->auth($password);      //密码验证
        $this->redis->select($db);    //选择数据库
    }

    public function setex($key, $time, $val)
    {
        return $this->redis->setex($key, $time, $val);
    }

    public function set($key, $val)
    {
        return $this->redis->set($key, $val);
    }

    public function get($key)
    {
        return $this->redis->get($key);
    }

    public function expire($key = null, $time = 0)
    {
        return $this->redis->expire($key, $time);
    }

    public function psubscribe($patterns = array(), $callback)
    {
        $this->redis->psubscribe($patterns, $callback);
    }

    public function setOption()
    {
        $this->redis->setOption(\Redis::OPT_READ_TIMEOUT, -1);
    }

    public function lRange($key,$start,$end)
    {
        return $this->redis->lRange($key,$start,$end);
    }

    public function lPush($key, $value1, $value2 = null, $valueN = null ){
        return $this->redis->lPush($key, $value1, $value2 = null, $valueN = null );
    }

    public function delete($key1, $key2 = null, $key3 = null)
    {
        return $this->redis->delete($key1, $key2 = null, $key3 = null);
    }

}

3、开启键值写入(index.php)

<?php
/**
 *  CREATE TABLE `agent`(
 *     `id` int(10) UNSIGNED NOT NULL,
 *     `code` varchar(10) NOT NULL,
 *      `status` tinyint(3) NOT NULL,
 *      `createtime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
 *  )ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='会员列表';
 */

require_once 'redis2.class.php';
$redis = new \Redis2('127.0.0.1','6379','','15');

//require_once 'db.class.php';
//$order_sn   = 'SN'.time().'T'.rand(10000000,99999999);
//$mysql = new \mysql();
//$mysql->connect();
//$data = ['code'=>$order_sn,'status'=>0,'createtime'=>date('Y-m-d H:i:s',time())];
//$mysql->insert('agent',$data);

$list = ['123456', 1];
$key = implode(':',$list);
$redis->setex($key,3,'redis延迟任务');      //3秒后回调
print_r($list);

/*
 *   测试其他key会不会有回调,结果:有回调
 *   $k = 'test';
 *   $redis2->set($k,'100');
 *   $redis2->expire($k,10);
 *
*/

4、过期事件的订阅(psubscribe.php)

<?php
// Linux环境需要加上下面一行代码,windows环境自主删除即可
#! /usr/bin/env php
ini_set('default_socket_timeout', -1);  //不超时
require_once 'redis2.class.php';
$redis_db = '15';
$redis = new \Redis2('127.0.0.1','6379','',$redis_db);
// 解决Redis客户端订阅时候超时情况
$redis->setOption();
//当key过期的时候就看到通知,订阅的key __keyevent@<db>__:expired 这个格式是固定的,db代表的是数据库的编号,由于订阅开启之后这个库的所有key过期时间都会被推送过来,所以最好单独使用一个数据库来进行隔离
$redis->psubscribe(array('__keyevent@'.$redis_db.'__:expired'), 'keyCallback');
// 回调函数,这里写处理逻辑
function keyCallback($redis, $pattern, $channel, $msg)
{
    echo PHP_EOL;
    echo "Pattern: $pattern\n";
    echo "Channel: $channel\n";
    echo "Payload: $msg\n\n";
    $list = explode(':',$msg);

    $code = isset($list[0])?$list[0]:'0';
    $use_mysql = isset($list[1])?$list[1]:'0';

    if($use_mysql == 1){
        require_once 'db.class.php';
        $mysql = new \mysql();
        $mysql->connect();
        $where = "code = '".$code."'";
        $mysql->select('agent','',$where);
        $finds=$mysql->fetchAll();
        print_r($finds);
        if(isset($finds[0]['status']) && $finds[0]['status']==0){
            $data   = array('status' => 3);
            $where  = " id = ".$finds[0]['id'];
            $mysql->update('agent',$data,$where);
        }
    }
}

//或者
/*$redis->psubscribe(array('__keyevent@'.$redis_db.'__:expired'), function ($redis, $pattern, $channel, $msg){
    echo PHP_EOL;
    echo "Pattern: $pattern\n";
    echo "Channel: $channel\n";
    echo "Payload: $msg\n\n";
    //................
});*/

结果
在这里插入图片描述

后台监听运行(linux)

1、命令

nohup php psubscribe.php > /dev/null 2>&1 &

2、查看进程

jobs -l 

3、杀死进程命令

kill -9 PID

参考文档
文档1
文档1

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值