当前位置: 首页 > 后端技术 > PHP

Redis实现队列

时间:2023-03-29 16:55:50 PHP

场景描述:用于处理比较耗时的请求,比如批量发送邮件。如果直接在网页触发发送,程序会出现超时和高并发的场景。当某个时刻请求瞬间增加时,你可以将请求写入队列,后台在处理这些请求。先进先出模式命令:rpush+blpoporlpush+brpoprpush:向链表右侧推送数据blpop:客户端阻塞,直到队列有值输出简单队列:simple.php$stmt=$pdo->prepare('selectid,cid,namefromzc_goodslimit200000');$stmt->execute();while($row=$stmt->fetch(PDO::FETCH_ASSOC)){$redis->rPush('货物:任务',json_encode($row));}$redis->close();获取2亿条数据,将json化后的数据推入goods:taskqueuequeueBlpop.php//Dequeuewhile(true){//阻塞超时时间为3秒$task=$redis->blPop(array('goods:task'),3);if($task){$redis->rPush('goods:success:task',$task[1]);$task=json_decode($task[1],true);回显$task['id']。':'。$任务['cid']。':'。'处理成功';echoPHP_EOL;}else{echo'nothing'.PHP_EOL;睡觉(5);}}设置blpop的阻塞时间为3秒,当有数据出队列时保存到goods:success:task表示执行成功。当队列没有数据时,程序休眠10秒,重新检查goods:task是否有数据出队列。在cli模式下执行命令:phpsimple.phpphpqueueBlpop.php优先队列思路:当blpop有多个key时,blpop会从左到右遍历key。一旦一个键可以弹出一个元素,客户端将立即返回。例如:blpopkey1key2key3key4从key1遍历到key4,如果有key有值,就会弹出这个value。如果多个key同时有值,左边的key会先弹出。priority.php//设置优先级队列$high='goods:high:task';$mid='goods:mid:task';$low='goods:low:task';$stmt=$pdo->prepare('selectid,cid,namefromzc_goodslimit200000');$stmt->execute();while($row=$stmt->fetch(PDO::FETCH_ASSOC)){//cid小于100的放在低级队列if($row['cid']<100){$redis->rPush($low,json_encode($row));}//100到600之间的cid被放入中间队列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';//Dequeuewhile(true){//优先级高的队列放在左边$task=$redis->blPop(array($high,$mid,$low),3);如果($task){$task=json_decode($task[1],true);回显$task['id']。':'。$任务['cid'].':'。'处理成功';echoPHP_EOL;}别的{回声'什么都没有'.PHP_EOL;睡觉(5);}}优先级高的队列放在blpop命令的左边,依次排序,blpop命令会依次弹出high、mid、low队列的值。cli方式执行命令:phppriority.phpphppriorityBlpop.php延迟队列思路:可以使用有序集合保存延迟任务,member保存任务内容,score保存(当前时间+延迟时间),时间为score。程序只需要将有序集中第一个任务的分数与当前时间进行比较即可。如果当前时间小于分数,则说明有序集中的所有任务都还没有到执行时间。delay.php$stmt=$pdo->prepare('selectid,cid,namefromzc_goodslimit200000');$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,所有任务delayHandle.phpwhile(true){//因为是有序集合,所以只判断第一条记录的延迟时间,比如第一条记录还没有到执行时间,则在1秒到300秒内被延迟执行//Relative表示集合的其他任务还没有到执行时间$rs=$redis->zRange('goods:delay:task',0,0,true);//集合没有任务,睡眠时间设置为5秒if(empty($rs)){echo'notasks,sleep5seconds'.PHP_EOL;睡觉(5);继续;}$taskJson=key($rs);$delay=$rs[$taskJson];$task=json_decode($taskJson,true);$现在=时间();//到时候执行延迟任务if($delay<=$now){//锁定当前任务,避免将延迟任务移动到任务队列时被其他客户端阻塞边修改if(!($identifier=acquireLock($task['id']))){继续;}//将延迟任务移动到任务队列$redis->zRem('goods:delay:task',$taskJson);$redis->rpush('货物:任务',$taskJson);回显$task['id']。'跑步'。PHP_EOL;//释放锁releaseLock($task['id'],$identifier);}else{//延迟任务的执行时间还没有到$sleep=$delay-$now;//最大值设置为2秒,保证如果有新任务(延迟时间为1秒)进入集合,可以及时处理//$sleep=$sleep>2?2:$睡眠;回声“等待”。$睡觉。'秒'。PHP_EOL;睡眠($睡眠);}}该文件处理有序集合中的延迟任务,如果延迟任务到达执行时间,将延迟任务移至任务队列queueBlpop.php//Dequeuewhile(true){//阻塞设置超时时间为3秒$task=$redis->blPop(array('goods:task'),3);if($task){$redis->rPush('goods:success:task',$task[1]);$task=json_decode($task[1],true);回显$task['id']。':'。$任务['cid'].':'。'处理成功';echoPHP_EOL;}else{回声'没有'。PHP_EOL;睡觉(5);以taskcli方式执行命令:phpdelay.phpphpdelayHanlde.phpphpqueueBlpop.php完整代码:https://github.com/wuzhc/demo...相关项目:https://github.com/wuzhc/gmq