场景说明:

·用于处理比较耗时的请求,例如批量发送邮件,如果直接在网页触发执行发送,程序会出现超时

·高并发场景,当某个时刻请求瞬间增加时,可以把请求写入到队列,后台在去处理这些请求

·抢购场景,先入先出的模式

命令:

rpush + blpop 或 lpush + brpop
rpush : 往列表右侧推入数据 
blpop : 客户端阻塞直到队列有值输出

简单队列:

simple.php
$stmt = $pdo->prepare('select id, cid, name from zc_goods limit 200000');$stmt->execute();while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {    $redis->rPush('goods:task', json_encode($row));} $redis->close();

获取20000万个商品,并把json化后的数据推入goods:task队列

queueBlpop.php
// 出队while (true) {    // 阻塞设置超时时间为3秒    $task = $redis->blPop(array('goods:task'), 3);    if ($task) {        $redis->rPush('goods:success:task', $task[1]);        $task = json_decode($task[1], true);        echo $task['id'] . ':' . $task['cid'] . ':' . 'handle success';        echo PHP_EOL;    } else {        echo 'nothing' . PHP_EOL;        sleep(5);    }}

设置blpop阻塞时间为3秒,当有数据出队时保存到goods:success:task表示执行成功,当队列没有数据时,程序睡眠10秒重新检查goods:task是否有数据出队

cli 模式执行命令:
php simple.phpphp queueBlpop.php

优先级队列

思路:

blpop 有多个键时,blpop会从左至右遍历键,一旦一个键能弹出元素,客户端立即返回。例如:

blpop key1 key2 key3 key4

从key1到key4遍历,如果哪个key有值,则弹出这个值,若多个key同时有值时,优先弹出排在左边的key。

priority.php
// 设置优先级队列$high = 'goods:high:task';
$mid = 'goods:mid:task';$low = 'goods:low:task';
 $stmt = $pdo->prepare('select id, cid, name from zc_goods limit 200000');
$stmt->execute();while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) 
{    // cid 小于100放在低级队列    if ($row['cid'] < 100) 
{        $redis->rPush($low, json_encode($row));    
}    // cid 100到600之间放在中级队列    elseif ($row['cid'] > 100 && $row['cid'] < 600) 
{        $redis->rPush($mid, json_encode($row));    }   
 // cid 大于600放在高级队列     else {        $redis->rPush($high, json_encode($row));    }
}$redis->close();
priorityBlop.php
// 优先级队列$high = 'goods:high:task';$mid = 'goods:mid:task';$low = 'goods:low:task';// 出队while(true){    // 优先级高的队列放在左侧    $task = $redis->blPop(array($high, $mid, $low), 3);    if ($task) {        $task = json_decode($task[1], true);        echo $task['id'] . ':' . $task['cid'] . ':' . 'handle success';        echo PHP_EOL;    } else {        echo 'nothing' . PHP_EOL;        sleep(5);    }}

优先级高的队列放在blpop命令左侧,依次排序,blpop命令会依次弹出high, mid, low队列的值

cli 模式执行命令:
php priority.phpphp priorityBlpop.php

延迟队列

思路:

可以用一个有序集合来保存延迟任务,member保存任务内容,score保存(当前时间 + 延时时间)。用时间作为score。程序只要用有序集合的第一条任务的score和当前时间做比较,如果当前时间比score小,说明有序集合的所有任务还没到执行时间。

delay.php
$stmt = $pdo->prepare('select id, cid, name from zc_goods limit 200000');$stmt->execute();while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {    $redis->zAdd('goods:delay:task', time() + rand(1, 300), json_encode($row));}

将20万条任务导入有序集合goods:delay:task,所有任务延迟到之后的1秒到300秒内执行

delayHandle.php

while (true) {// 因为是有序集合,只要判断第一条记录的延时时间,例如第一条未到执行时间    // 相对说明集合的其他任务未到执行时间

$rs = $redis->zRange('goods:delay:task', 0, 0, true);

// 集合没有任务,睡眠时间设置为5秒

    if (empty($rs)) {        
                echo 'no tasks , sleep 5 seconds' . PHP_EOL;sleep(5);continue;}
     $taskJson = key($rs);   
              $delay = $rs[$taskJson];   
              $task = json_decode($taskJson, true);   
      $now = time();// 到时间执行延时任务   
     if ($delay <= $now) {       

// 对当前任务加锁,避免移动移动延时任务到任务队列时被其他客户端修改

        if (!($identifier = acquireLock($task['id']))) {         
       continue;}        

// 移动延时任务到任务队列

$redis->zRem('goods:delay:task', $taskJson);        
$redis->rPush('goods:task', $taskJson);       
echo $task['id'] . ' run ' . PHP_EOL;        

// 释放锁

releaseLock($task['id'], $identifier);    } 
    else {       

// 延时任务未到执行时间

 $sleep = $delay - $now;       

// 最大值设置为2秒,保证如果有新的任务(延时时间1秒)进入集合时能够及时的被处理

    $sleep = $sleep > 2 ? 2 :$sleep;       
    echo 'wait ' . $sleep . ' seconds ' . PHP_EOL;        sleep($sleep);   
    }
}

这个文件对有序集合内的延迟任务做处理,如果延迟任务到了执行时间,则把延迟任务移动到任务队列中

queueBlpop.php
// 出队while (true) {   
// 阻塞设置超时时间为3秒   
$task = $redis->blPop(array('goods:task'), 3);   
if ($task) {       
$redis->rPush('goods:success:task', $task[1]);       
$task = json_decode($task[1], true);       
echo $task['id'] . ':' . $task['cid'] . ':' . 'handle success';       
echo PHP_EOL;    } else {       
echo 'nothing' . PHP_EOL;sleep(5);   
    }
}

处理任务队列中的任务

cli模式下执行命令:
php delay.phpphp delayHanlde.phpphp queueBlpop.php

Redis 实现队列http://igeekbar.com/igeekbar/post/436.htm的更多相关文章

  1. redis消息队列简单应用

    消息队列出现的原因 随着互联网的高速发展,门户网站.视频直播.电商领域等web应用中,高并发.大数据已经成为基本的标识.淘宝双11.京东618.各种抢购.秒杀活动.以及12306的春运抢票等,他们这些 ...

  2. (转)java redis使用之利用jedis实现redis消息队列

    应用场景 最近在公司做项目,需要对聊天内容进行存储,考虑到数据库查询的IO连接数高.连接频繁的因素,决定利用缓存做. 从网上了解到redis可以对所有的内容进行二进制的存储,而java是可以对所有对象 ...

  3. 分布式日志2 用redis的队列写日志

    using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.We ...

  4. logstash解耦之redis消息队列

    logstash解耦之redis消息队列 架构图如下: 说明:通过input收集日志消息放入消息队列服务中(redis,MSMQ.Resque.ActiveMQ,RabbitMQ),再通过output ...

  5. 预热一下吧《实现Redis消息队列》

    应用场景 为什么要用redis?二进制存储.java序列化传输.IO连接数高.连接频繁 一.序列化 这里编写了一个java序列化的工具,主要是将对象转化为byte数组,和根据byte数组反序列化成ja ...

  6. Redis分布式队列解决文件并发的问题

    1.首先将捕获的异常写到Redis的队列中 public class MyExceptionAttribute : HandleErrorAttribute { public static IRedi ...

  7. 【高并发简单解决方案】redis缓存队列+mysql 批量入库+php离线整合

    原文出处: 崔小拽 需求背景:有个调用统计日志存储和统计需求,要求存储到mysql中:存储数据高峰能达到日均千万,瓶颈在于直接入库并发太高,可能会把mysql干垮. 问题分析 思考:应用网站架构的衍化 ...

  8. RabbitMQ与Redis做队列比较

    本文仅针对RabbitMQ与Redis做队列应用时的情况进行对比 具体采用什么方式实现,还需要取决于系统的实际需求简要介绍RabbitMQRabbitMQ是实现AMQP(高级消息队列协议)的消息中间件 ...

  9. Redis 消息队列的实现

    概述 Redis实现消息队列有两种形式: 广播订阅模式:基于Redis的 Pub/Sub 机制,一旦有客户端往某个key里面 publish一个消息,所有subscribe的客户端都会触发事件 集群订 ...

  10. java-spring基于redis单机版(redisTemplate)实现的分布式锁+redis消息队列,可用于秒杀,定时器,高并发,抢购

    此教程不涉及整合spring整合redis,可另行查阅资料教程. 代码: RedisLock package com.cashloan.analytics.utils; import org.slf4 ...

随机推荐

  1. LINUX 内核 API

    http://www.compsoc.man.ac.uk/~moz/kernelnewbies/documents/kdoc/kernel-api/linuxkernelapi.html

  2. TCP选项之SO_RCVBUF和SO_SNDBUF

    每个TCP socket在内核中都有一个发送缓冲区和一个接收缓冲区,TCP的全双工的工作模式以及TCP的滑动窗口便是依赖于这两个独立的buffer以及此buffer的填充状态.接收缓冲区把数据缓存入内 ...

  3. Apache Kafka —一个不同的消息系统

    Apache已经发布了Kafka 0.8,也是自从成为Apache软件基金会的顶级项目后Kafka的 第一个主版本. Apache Kafka是发布—订阅消息传递,实现了分布式提交日志,适用于离线和在 ...

  4. IIS7.5标识介绍

    应用程序池的标识是运行应用程序池的工作进程所使用的服务帐户名称.默认情况下,应用程序池以 Network Service 用户帐户运行,该帐户拥有低级别的用户权限.您可以将应用程序池配置为以 Wind ...

  5. C# CSGL

    转.修改自ShareIdeas文章C# 基于CSGL opengl OpenGL是一个功能强大的开放图形库(Open Graphics Library).其前身是SGI公司为其图形工作站开发的IRIS ...

  6. ssh 多条命令执行

    格式:ssh user@ip command 单条命令:ssh user@ip command1 多条命令:ssh user@ip "command1;command2" 不加双引 ...

  7. rtorrent - 强大的命令行BT客户端

    NOTE - 文中展示的所有示例和指令都已经在Ubuntu 13.04中测试过. 一.            安装 [root@GY-10000 data]# yum search rtorrent ...

  8. c++ #ifdef的用法

    http://www.tuicool.com/articles/mIJnumB #ifdef的用法 灵活使用#ifdef指示符,我们可以区隔一些与特定头文件.程序库和其他文件版本有关的代码.代码举例: ...

  9. C/C++中const关键字

    http://blog.csdn.net/xdrt81y/article/details/24333335 今天在做一个趋势笔试题的时候,才让我有了系统把const关键字好好总结一下的冲动,因为这个关 ...

  10. Redis客户端集群

        1.Redis集群一般分为两类,即3.0版本后的服务端集群实现,3.0版本前的客户端集群实现,服务端集群即Redis Cluster(官方实现),采用slot槽的概念(分片,所有服务端redi ...