订阅发布延时_Redis实时队列和延时队列的php实现

f8cdd490952e918c9f3a4d7b496959bb.png

Redis是一个开源的,基于内存的数据结构存储器,用作数据库,缓存和消息中间件。支持的数据结构有strings, hashes, lists, sets, sorted sets。详细可参考redis官方介绍,本文介绍如何利用Redis来实现实时队列和延时队列,测试环境为Docker,编程语言是php并安装phpredis扩展。

环境搭建

创建根目录test,然后在test目录里面创建Dockerfile文件和docker-composer.yml文件,内容如下:

Dockerfile
FROM php:7.4.11-cli-alpine3.12
LABEL MAINTAINER="redistest"
ENV ROOT_PATH /webapp
WORKDIR ${ROOT_PATH}
RUN mkdir -p ${ROOT_PATH} && 
   cp /usr/local/etc/php/php.ini-production /usr/local/etc/php/php.ini && 
   sed -i 's/;date.timezone =/date.timezone = PRC/g' /usr/local/etc/php/php.ini && 
   sed -i 's/upload_max_filesize = 2M/upload_max_filesize = 8M/g' /usr/local/etc/php/php.ini && 
   sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories && 
   apk update && 
   apk add gcc g++ automake autoconf libtool make
RUN  pecl install http://pecl.php.net/get/redis-5.1.1.tgz && docker-php-ext-enable redis
RUN  apk add supervisor && echo_supervisord_conf
CMD supervisord -n -c /etc/supervisord.conf
docker-composer.yml
version: '3'
services:
    redis-test:
        build: 
          context: .
          dockerfile: ./Dockerfile
        image: redis-test
        working_dir: /webapp
        volumes:
          - ./:/webapp
        links: 
          - redis
    redis:
      image: redis:5.0.6-alpine
      command: redis-server --notify-keyspace-events Ex

实时队列

使用lists数据结构,生产者将消息(数据)入队,消费者将消息出队后处理业务逻辑。

生产者producter.php
$redis = new Redis();
$redis->connect('redis',6379); //连接redis
$key = 'queue'; //队列名
$redis->rPush($key,1,2); //向队列右侧入队数据1和2
消费者consumer.php
$redis = new Redis();
$redis->connect('redis',6379); //连接redis
$key = 'queue'; //队列名
while(true){ //死循环
 while($value = $redis->blPop($key,5)){ //队列左侧出队(阻塞式)
 //处理业务逻辑
        echo $value[1];
        echo PHP_EOL;
    }
}

延时队列

一,使用sorted sets数据结构,score存储时间戳(timestamp)。
$redis = new Redis();
$redis->connect('redis',6379); //连接redis
$key = 'queue'; //队列名
$time = time();
for($i=$time-20;$i<$time;++$i){
    $redis->zAdd($key,$i,$i.'-val'); //写入测试数据
}
while(true){ //死循环出队
    $r = $redis->multi()->zRangeByScore($key,0,$time)->zRemRangeByScore($key,0,$time)->exec();
    if(isset($r[0])){
        foreach($r[0] as $value){
            //处理逻辑
            echo $value;
            echo PHP_EOL;
        }
    }
}
二,使用redis的发布,订阅过期key通知。
$redis = new Redis();
$redis->connect('redis',6379); //连接redis
for($i=1;$i<=3;++$i){
    $time = time() + $i;
    $key = 'key_exp_'.$time;
    $val = $time.'-val';
    $redis->set($key,$val,['nx', 'ex'=>$i]);//设置过期key
}

//订阅key过期事件
$redis->psubscribe(array('__keyevent@0__:expired'), function($redis, $pattern, $chan, $msg){
    echo "Pattern: $patternn";
    echo "Channel: $chann";
    echo "Payload: $msgnn";
});

执行

打开终端,切换到根目录test里,启动服务命令如下:

docker-compose up

829b9ac70356075d0cdfd81b91c36176.png

在终端打开新窗口,进入容器命令如下:

docker exec -it redis_redis-test_1 sh

907d175a69d6fc0b59ccba0115fb1753.png

910c7317fdaf58f504d3d82100465dc7.png

总结与思考

利用Redis能够实现实时队列和延时队列的功能,但优势和缺点都同样非常明显,优势就是配置简单,使用方便快捷。缺点是消费者出队后在处理逻辑的过程若进程因意外死了数据会丢失,而且上例中延时队列只适合处理小量消息。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值