php使用redis实现延时队列

成何
• 阅读 3904

延时队列用途

  • 订单30分钟未支付自动取消

实现方式

  • 轮询mysql
  • redis zset
  • RabbitMQ
  • 其他开源实现

mysql轮询效率低,一般不考虑使用,这里主要使用redis zset来实现

Redis Zset

原理

1.向zset中插入数据
score保存订单超时时间戳,订单如果30s后超时,将当时时间戳+30即可
value保存订单ID
2.轮询zset
根据score值范围查询【0,当前时间戳】即为要处理的订单
使用zrem删除此订单ID,若删除成功就开始处理订单超时逻辑

源码

<?php

Class DelayQueue
{
    public $redis;

    /**
     * 连接mysql
     * DelayQueue constructor.
     * @throws Exception
     */
    public function __construct()
    {
        $redis = new \Redis();
        $res   = $redis->connect('127.0.0.1', 6379, 5);
        if ($res === false) {
            throw new Exception('连接失败');
        }
        $this->redis = $redis;
    }

    /**
     * 插入延时队列
     * @param $key
     * @param $value
     * @param $score
     * @throws Exception
     */
    public function set($key, $value, $score)
    {
        $res = $this->redis->zAdd($key, ['NX'], $score, $value);
        if ($res == 0) {
            throw new Exception('入队列失败');
        }
    }

    /**
     * 处理延时队列
     * @param $key
     */
    public function deal($key)
    {
        while (true) {
            $res = $this->redis->zRangeByScore($key, 0, time(), ['limit' => [0, 1]]);
            echo '正常处理' . PHP_EOL;
            if (empty($res)) {
                sleep(1);
                continue;
            }
            $value = $res[0];
            $res   = $this->redis->zRem($key, $value);
            //在多线程处理时,只有删除成功的才有订单处理权
            if ($res) {
                //处理订单处理逻辑,更新订单状态,给用户发送提醒消息
                var_dump(sprintf("订单【%s】30分钟未支付,已自动取消", $value));
                //如果这里的任务处理失败,需要重新加入延时队列
            }
        }
    }
}

$model = new DelayQueue();
//zset key名
$key = "order:delayqueue";
// 订单ID
$ordId = "S000001";
$model->set($key, $ordId, time() + 10);//10s之后处理
$ordId = "S000002";
$model->set($key, $ordId, time() + 30);//30s之后处理
$ordId = "S000003";
$model->set($key, $ordId, time() + 60);//60s之后处理

$model->deal($key);

运行效果

php使用redis实现延时队列

总结

优点

  • 实现简单

缺点

  • 轮询redis,会造成无用的IO消耗
  • 可能有1s延时
  • 只有单线程处理
点赞
收藏
评论区
推荐文章
Wesley13 Wesley13
4年前
STM32延时函数的四种方法
单片机编程过程中经常用到延时函数,最常用的莫过于微秒级延时delay\_us()和毫秒级delay\_ms()。本文基于STM32F207介绍4种不同方式实现的延时函数。1、普通延时这种延时方式应该是大家在51单片机时候,接触最早的延时函数。这个比较简单,让单片机做一些无关紧要的工作来打发时间,经常用循环来实现,在某些编译器下,代码会被
一种异步延迟队列的实现方式
目前系统中有很多需要用到延时处理的功能:支付超时取消、排队超时、短信、微信等提醒延迟发送、token刷新、会员卡过期等等。通过延时处理,极大的节省系统的资源,不必轮询数据库处理任务。今天,就来介绍一种异步延迟队列的实现方式
Stella981 Stella981
4年前
Spring Boot(十四)RabbitMQ延迟队列
一、前言延迟队列的使用场景:1.未按时支付的订单,30分钟过期之后取消订单;2.给活跃度比较低的用户间隔N天之后推送消息,提高活跃度;3.过1分钟给新注册会员的用户,发送注册邮件等。实现延迟队列的方式有两种:1.通过消息过期后进入死信交换器,再由交换器转发到延迟消费队列,实现延迟功能;2.使用rabbitmqdelayed
Stella981 Stella981
4年前
Nginx + lua +[memcached,redis]
精品案例1、Nginxluamemcached,redis实现网站灰度发布2、分库分表/基于Leaf组件实现的全球唯一ID(非UUID)3、Redis独立数据监控,实现订单超时操作/MQ死信操作SelectPollEpollReactor模型4、分布式任务调试Quartz应用
Stella981 Stella981
4年前
Nginx的负载均衡
上篇blog讲述了加权轮询算法的原理、以及负载均衡模块中使用的数据结构,接着我们来看看加权轮询算法的具体实现。 指令的解析函数 如果upstream配置块中没有指定使用哪种负载均衡算法,那么默认使用加权轮询。也就是说使用加权轮询算法,并不需要特定的指令,因此也不需要实现指令的解析函数。而实际上,和其它负载均衡算法不同(比如ip\_ha
Stella981 Stella981
4年前
Redis发布订阅(Pub
一、redis做消息队列1\.redis存储的list数据是双向链表实现的,可以作为队列2\.使用lpush和rpop实现入队和出队3\.每次使用lpush和rpop都要发起一次连接,性能不好4\.这是一次生产,一次消费的队列二、发布/订阅模式(publish/subscribe),也是作为消息队列1\.可以一次生产
Easter79 Easter79
4年前
Swoole2.0协程客户端连接池的实现
Swoole2.0官方默认的实例是短连接的,在请求处理完毕后就会切断redis或mysql的连接。实际项目可以使用连接池实现复用。实现原理也很简单,使用SplQueue,在请求到来时判断资源队列中是否有可用的连接,如果有直接拿来复用。如果没有就创建一个新的连接。在连接使用完毕后再讲它重新放回到队列,此连接就可以被其他协程复用。$count
Stella981 Stella981
4年前
RocketMQ进阶
点击上方 蓝字关注我们!(https://oscimg.oschina.net/oscnet/20e072a82485498eaa440946d09e98d6.jpg)前言在开发中经常会遇到延时任务的需求,例如在12306购买车票,若生成订单30分钟未支付则自动取消;还有在线商城完成订单后48小时不评价,自动5星好评
Stella981 Stella981
4年前
Redis官网——如何利用Redis做服务器集群的分布式锁
链接:http://redis.io/topics/distlock(https://www.oschina.net/action/GoToLink?urlhttp%3A%2F%2Fredis.io%2Ftopics%2Fdistlock)原理很简单,一段时间内轮询加锁的key重点,不同语言的开源实现Beforedescribingth
Stella981 Stella981
4年前
Redis(四)——消息队列
Redis不仅可作为缓存服务器,还可用作消息队列。它的列表类型天生支持用作消息队列。\\性质:\\由于Redis的列表是使用双向链表实现的,保存了头尾节点,所以在列表头尾两边插取元素都是非常快的。所以可以直接使用Redis的List实现消息队列,只需简单的两个指令lpush和rpop或者rpush和lpop。(列表常用命令)R
Stella981 Stella981
4年前
Spring Boot与RabbitMQ结合实现延迟队列的示例
背景何为延迟队列?顾名思义,延迟队列就是进入该队列的消息会被延迟消费的队列。而一般的队列,消息一旦入队了之后就会被消费者马上消费。场景一:在订单系统中,一个用户下单之后通常有30分钟的时间进行支付,如果30分钟之内没有支付成功,那么这个订单将进行一场处理。这是就可以使用延时队列将订单信息发送到延时队列。场景二:用户希望通过手机远程遥控
成何
成何
Lv1
我也怕你会在我看不见的地方陪着别人.
文章
2
粉丝
0
获赞
0