Laravel框架中队列的原理是什么
创始人
2024-12-07 12:07:04
0次

Laravel 是什么

Laravel 是一套简洁、优雅的PHP Web开发框架。它可以让你从面条一样杂乱的代码中解脱出来;它可以帮你构建一个完美的网络APP,而且每行代码都可以简洁、富于表达力。

原理分析

创建分发任务方法

class TestController extends Controller
{
  //其他方法
  //发送消息
  public function SendMessage(Request $request){
    ...
    $this->dispatch((new SendMessage($sendParams))->onQueue('snail:SendMessage'));
  }
}

内部实现:

Laravel框架中队列的原理是什么

创建消费任务

命令行运行如下命令:

/home/niuyufu/php/bin/php /home/niuyufu/webroot/assistant_api/artisan queue:work --queue=snail:SendMessage --tries=3 --memory=512 --daemon

内部实现:

Laravel框架中队列的原理是什么

队列消息分析:

监控redis对应队列消息,具体产生的消息操作,如下:

tail -f | redis-cli -h 10.94.120.13 -p 6380 monitor | grep "queues:snail"
1492446053.406282 [0 10.95.117.155:57132] "WATCH" "queues:snail:SendMessage:delayed"
1492446053.406452 [0 10.95.117.155:57132] "ZRANGEBYSCORE" "queues:snail:SendMessage:delayed" "-inf" "1492446053"
1492446053.406754 [0 10.95.117.155:57132] "WATCH" "queues:snail:SendMessage:reserved"
1492446053.406842 [0 10.95.117.155:57132] "ZRANGEBYSCORE" "queues:snail:SendMessage:reserved" "-inf" "1492446053"
1492446053.407029 [0 10.95.117.155:57132] "LPOP" "queues:snail:SendMessage"
1492446053.407700 [0 10.95.117.155:57132] "ZADD" "queues:snail:SendMessage:reserved" "1492446113" "{job}"
1492446053.463953 [0 10.95.117.155:57132] "ZREM" "queues:snail:SendMessage:reserved" "{job}"

PS:如果你的redis是codis的话,注意了,因为codis禁用方法列表

KEYS, MOVE, OBJECT, RENAME, RENAMENX, SORT, SCAN, BITOP,MSETNX, BLPOP, BRPOP, BRPOPLPUSH, PSUBSCRIBE,PUBLISH, PUNSUBSCRIBE, SUBSCRIBE, UNSUBSCRIBE, DISCARD, EXEC, MULTI, UNWATCH, WATCH, SCRIPT EXISTS, SCRIPT FLUSH, SCRIPT KILL, SCRIPT LOAD, AUTH, ECHO, SELECT, BGREWRITEAOF, BGSAVE, CLIENT KILL, CLIENT LIST, CONFIG GET, CONFIG SET, CONFIG RESETSTAT, DBSIZE, DEBUG OBJECT, DEBUG SEGFAULT, FLUSHALL, FLUSHDB, INFO, LASTSAVE, MONITOR, SAVE, SHUTDOWN, SLAVEOF, SLOWLOG, SYNC, TIME

所以执行消费任务会有以下错误:

[Predis\Connection\ConnectionException]
Error while reading line from the server. [tcp://100.90.154.39:3000]

解决方法为修改config/queue.php

'redis' => [
  'driver' => 'redis',
  'connection' => 'default',
  'queue' => 'default',
  'expire' => null,  //禁用即可
],

优化日志处理:

如果你的系统有切割文件日志操作。会发现虽然日志被切分了,但程序却没有往新文件里写入。如,2017-04-18 13:50启动的项目,日志会一直打到 snail.log.2017041813上。

改进方案:

app/Jobs/Job.php文件中添加如下方法:

public function releaseLoggerFile(){
  $handles=\Log::getMonolog()->getHandlers();
  if(!is_array($handles) || empty($handles)){
    return;
  }
  foreach($handles as $handle){
    if(method_exists($handle, "close")){
      $handle->close();
    }
  }
  return;
}

在具体job实现类中的handle方法结尾添加:

public function handle()
{
  ...
  $this->releaseLoggerFile(); //释放log文件
}

线上部署

创建任务shell

#!/bin/sh
day=$(date +'%y%m%d')
now=$(date +"%F %T")
php_command="/home/niuyufu/php/bin/php"
command="/home/niuyufu/webroot/snail_api/artisan"
log="/home/niuyufu/webroot/log/wave"
queue_name_arr=("snail:SendMessage" "snail:SendMessageToApp")
case $1 in
"run")
  for queue_name in ${queue_name_arr[*]}
  do
    count=$(ps aux | grep artisan |grep queue=${queue_name} | grep -v grep | wc -l)
    if [ ${count} -lt 1 ];then
      echo "${now}:${queue_name} process has exit ${count}\n";
      nohup $php_command $command queue:work --queue=${queue_name} --tries=3 --memory=512 --daemon >> $log/queueMonitor.log 2>&1 &
    else
      echo "${now}:${queue_name} process is runing";
    fi
  done
  ;;
"stop")
  kill -9 $(ps -ef | grep "queue:work" | grep -v grep | awk '{print $2}' | tr -s '\n' ' ')
  echo ${now}."Queue process all stop";
  ;;
"list")
  ps -ef | grep "queue:work" | grep -v grep
  ;;
*)
  echo "
Usage: QueueMonitorCommandShell.sh [run|stop|list]
  "
  ;;
esac

总结:

laravel这边的延迟队列使用了三个队列。

queue:default:delayed // 存储延迟任务
queue:default // 存储"生"任务,就是未处理任务
queue:default:reserved // 存储待处理任务
任务在三个队列中进行轮转,最后一定进入到queue:default:reserved,并且成功后把任务从这个队列中删除。

laravel5.1 使用了watch来控制队列的原子操作,但由于codis本身不支持 watch 方法。所以使用codis不能完全体验队列功能:延迟队列不支持、不支持数据重跑,对线上数据比较严格操作谨慎使用。

laravel5.3 之后redis队列 开始使用lua脚本支持的队列原子操作,它没有使用 watch multi等操作,所以如果线上codis 支持lua的话,可以完整体验到队列功能。

相关内容

热门资讯

空调连续工作多久需要停机休息 空调连续工作的时间取决于多个因素,包括空调的型号、功率、使用环境和维护情况等。一般来说,空调可以连续...
空调哪个符号是除湿的 空调除湿功能通常用一个水滴形状的符号表示。不同品牌和型号的空调遥控器可能会有所差异,但一般来说,除湿...
格力空调多长时间加一次氟利昂 1、一般情况下,空调对氟利昂的使用量是非常小的,所以在空调使用了四年左右的时候再考虑加也没问题。2、...
空调用多长时间需要加氟一次 一般情况下是五年。当出现以下这几种情况时,空调才需要加氟。1、空调的室内机和室外机各有两个接口,当接...
格调生活·C标思享荟:卡萨帝在... 9月12日的郑州龙湖金融岛,夜风轻拂,灯光璀璨。“C标时刻共传奇——卡萨帝思享荟暨20周年品牌盛典郑...
品牌价值破千亿、高端份额持续领... 9月12日,“C标时刻共传奇——卡萨帝思享荟暨20周年品牌盛典郑州站”在郑州龙湖金融岛举办。2026...
空调主板坏了修800还是换新的 空调主板坏了是修还是换新,需要考虑多个因素,以下是一些建议:1. 维修成本:如果维修费用较低,比如 ...
空调开多久需要休息多长时间 问题:空调开多久需要休息多长时间回答:1、在使用空调的过程中,一般空调开7~8个小时左右需要休息2~...
中央空调多长时间清洗一次 1、一般空调开机前清洗一次即可,空调开机中间时段再清洗一次,空调关机时清洗一次,这样比较合理。2、空...
中央空调氟利昂多久加一次 看空调制热和制冷程度,很多人的观点认为氟利昂必须一年放一次,其实这个观点是错误的,理解上面有点偏差,...