消费信息如下ThinkPHP5 Queue消息队列

优点

1、Queue内置了 Redis,Database,Topthink ,Sync这四种驱动,本文使用Redis驱动

2、Queue消息队列适用于大并发或者返回结果 时间有点长并需要批量操作的第三方接口,可用于短信发送、邮件发送、APP推送

3、Queue消息消息可进行发布,获取,执行,删除,重发,失败处理,延迟执行,超时控制等操作

流程图

  

创建队列

文件路径:application\common\queue\TestQueue.php

TestQueue.php 参考代码

  

<?php
namespace app\common\queue; use think\facade\Log;
use think\queue\Job; class TestQueue
{
public function fire(Job $job, $data)
{
$isJobDone = $this->testJob($data);
// 如果任务执行成功后 记得删除任务,不然这个任务会重复执行,直到达到最大重试次数后失败后,执行failed方法
if ($isJobDone) {
$job->delete();
} else {
//通过这个方法可以检查这个任务已经重试了几次了
$attempts = $job->attempts();
echo $attempts;
if ($attempts == 0 || $attempts == 1) {
// 重新发布这个任务
$job->release(2); //$delay为延迟时间,延迟2S后继续执行
} elseif ($attempts == 2) {
$job->release(5); // 延迟5S后继续执行
}
}
} /**
* @Desc: 任务执行失败后自动执行方法
* @param $data
*/
public function failed($data)
{
// ...任务达到最大重试次数后,失败了
Log::error('任务达到最大重试次数后,失败了 '.json_encode($data));
} /**
* @Desc: 自定义需要加入的队列任务
*/
private function testJob($data)
{
$jsonData = json_encode($data);
echo "1、具体执行任务接受到的参数:{$jsonData} \r\n";
if($data){
echo "2、恭喜你!{$data['email']} 邮件发送成功了 \r\n";
return true;
}else{
echo "2、很遗憾,{$data['email']} 邮件发送失败了 \r\n";
return false;
}
}
}

  

配置队列

1、这里使用Redis驱动来存储队列消息

2、队列配置文件路径:application\config\queue

配置参考代码

  

return [
'connector' => 'Redis',
'expire' => 3600,
'default' => 'REDIS_QUEUE',
'host' => 'dnmp-redis',
'port' => 6379,
'password' => '',
'select' => 0,
'timeout' => 0,
'persistent' => false,
];

  生产者参考代码

    

/**
* @Desc: 生产者生产消息
*/
public function productMsg()
{
// 当前任务所需的业务数据,不能为 resource 类型,其他类型最终将转化为json形式的字符串
$data = [
'email' => rand(11,99).'@qq.com',
'username' => 'Tinywan'
]; // 当前任务归属的队列名称,如果为新队列,会自动创建
$queueName = 'testQueue'; // 将该任务推送到消息队列,等待对应的消费者去执行
$isPushed = Queue::push(TestQueue::class, $data, $queueName); // database 驱动时,返回值为 1|false; redis驱动时,返回值为 随机字符串|false
if ($isPushed !== false) {
echo '['.$data['email'].']'." 队列加入成功 \r\n";
} else {
echo "队列加入失败 \r\n";
}
}

  

为了方便演示,这里使用cli模式。

执行生产者:php product_msg.php

# php product_msg.php
[27@qq.com] 队列加入成功
# php product_msg.php
[77@qq.com] 队列加入成功

  

1、这时候消息已经被持久化到Redis中去了(通过列表去存储)

2、推送成功,虽然我们这时候已经写好了消费者,但是我们并没有开始消费。但是推送消息依然是成功的。这个就是中间件的优势。他连接两个系统,但是又不会互相耦合,生产者并不会因为消费者的异常而影响到自己。

3、消息推送成功之后,如果没有消费者,消息会堆积在队列中。不过别怕,消息堆积很正常,并且一般的中间件堆积能力是非常强的。比如阿里就宣传自己mq可以堆积上亿条数据。

查看Redis消息与队列

> docker exec -it dnmp-redis redis-cli
127.0.0.1:6379> keys *
127.0.0.1:6379> keys *
1) "queues:testQueue"
127.0.0.1:6379> TYPE queues:testQueue
list
127.0.0.1:6379> LRANGE queues:testQueue 0 -1
1) "{\"job\":\"app\\\\common\\\\queue\\\\TestQueue\",\"data\":{\"email\":\"27@qq.com\",\"username\":\"Tinywan\"},\"id\":\"MLgNb4LFALhtmp7HZtfXMFPRUT0r94Bi\",\"attempts\":1}"
2) "{\"job\":\"app\\\\common\\\\queue\\\\TestQueue\",\"data\":{\"email\":\"77@qq.com\",\"username\":\"Tinywan\"},\"id\":\"JM16vvjMylfJDnOpldJaHda8xMwuYYzP\",\"attempts\":1}"
127.0.0.1:6379>

消费者

开始消费消息。执行cli 命令 php think queue:work--queue队列名称

# php think queue:work --queue testQueue
1、具体执行任务接受到的参数: {"email":"27@qq.com","username":"Tinywan"}
2、恭喜你!27@qq.com 邮件发送成功了
Processed: app\common\queue\TestQueue

  

这里每消费掉一条消息,Redis数据库中将会减少一条消息

查看Redis队列消息

127.0.0.1:6379> LRANGE queues:testQueue 0 -1
1) "{\"job\":\"app\\\\common\\\\queue\\\\TestQueue\",\"data\":{\"email\":\"77@qq.com\",\"username\":\"Tinywan\"},\"id\":\"JM16vvjMylfJDnOpldJaHda8xMwuYYzP\",\"attempts\":1}"
127.0.0.1:6379>

  命令行挂起守护进程执行

/usr/bin/php /var/www/tp5/think queue:work --daemon --queue testQueue --memory 256

  

--daemon 是否循环执行,如果不加该参数则该命令处理完下一个消息就退出 --queue 要处理的队列的名称 --delay 0 如果本次任务执行抛出异常且任务未被删除时,设置其下次执行前延迟多少秒,默认为0。 --memory 该进程允许使用的内存上限,以M为单位。

流程图

  

消费信息如下

 php think queue:work --daemon --queue testQueue
1、具体执行任务接受到的参数: {"email":"77@qq.com","username":"Tinywan"}
2、恭喜你!77@qq.com 邮件发送成功了
Processed: app\common\queue\TestQueue
1、具体执行任务接受到的参数: {"email":"80@qq.com","username":"Tinywan"}
2、恭喜你!80@qq.com 邮件发送成功了
Processed: app\common\queue\TestQueue
1、具体执行任务接受到的参数: {"email":"34@qq.com","username":"Tinywan"}
2、恭喜你!34@qq.com 邮件发送成功了
Processed: app\common\queue\TestQueue

  

1、命令行模式可以常驻内存不停的执行php代码。这样就可以达到类似于静态语言的java的效果。

2、一开始监听队列。刚刚在队列中堆积的消息立刻就被获取到,开始执行了代码。最后执行完成,删除了消息。

3、在 queue:work--daemon 单进程循环消费的时候,改了代码是不会生效的。这时脚本语言有点类似于静态语言在执行。所以需要我们用 queue:restart 重启 work 进程 。

命令行挂起守护进程执行

/usr/local/php/bin/php    /data/wwwroot/default/thinkphp_5/think    queue:work --daemon --queue testQueue --memory 256

  查看进程是否在运行

# ps
PID USER TIME COMMAND
1 root 0:00 php-fpm: master process (/usr/local/etc/php-fpm.conf)
6 www-data 0:00 php-fpm: pool www
7 www-data 0:00 php-fpm: pool www
16 root 0:00 sh
56 root 0:00 sh
113 root 0:00 php think queue:work --daemon --queue testQueue

  你再也不用守在终端了,以后只负责生产消息就可以了。Redis队列也不会积累消息了

其他(中间件)

中间件系统的定义是两个独立的不同的系统在中间构建起传递消息的工具。但是同一个系统也可以通过中间件来榨取性能,大家肯定项目中遇到过性能瓶颈。

比如发送邮件,发送短信,转换视频格式等等。这些业务都是比较耗性能,又对先后顺序不敏感的业务。这种业务就非常适合使用消息队列系统来异步处理,使性能提升。

重启队列和生成队列

TP5系列 | Queue消息队列的更多相关文章

  1. 进程间通信系列 之 消息队列函数(msgget、msgctl、msgsnd、msgrcv)及其范例

    进程间通信系列 之 概述与对比   http://blog.csdn.net/younger_china/article/details/15808685  进程间通信系列 之 共享内存及其实例   ...

  2. php消息队列之 think queue消息队列初体验

    使用thinkphp 5的  消息队列 think queue ● php think queue:listen --queue queuename ● php think queue:work -- ...

  3. think queue 消息队列初体验

    使用的是tp5  自带的消息队列 thinkphp top里的 消息队列框架 think-queue 这是thinkphp官方团队开发的一个专门支持队列服务的扩展包 消息队列应用场景: 消息队列适用于 ...

  4. [2017-10-25]Abp系列——集成消息队列功能(基于Rebus.Rabbitmq)

    本系列目录:Abp介绍和经验分享-目录 前言 由于提交给ABP作者的集成消息队列机制的PR还未Review完成,本篇以Abplus中的代码为基准来介绍ABP集成消息队列机制的方案. Why 为什么需要 ...

  5. Redis系列(三)--消息队列、排行榜等

    Redis命令执行生命周期: 发送命令--->排队(单线程)--->执行命令--->返回结果 慢查询: 只是针对命令执行阶段 慢查询日志通过一个固定长度的FIFO queue,这个q ...

  6. C++ message queue 消息队列入门

    说明:当我们有多个线程以不同的速度运行并且我们想要以特定的顺序从一个线程向另一个线程发送信息时,消息队列可能会有用. 这个想法是,发送线程将消息推送到队列中,而接收线程将消息按自己的步调弹出. 只要发 ...

  7. queue消息队列

    class queue.Queue(maxsize=0) #先入先出 class queue.LifoQueue(maxsize=0) #last in fisrt out  class queue. ...

  8. Python中queue消息队列模块

    from queue import Queue from queue import PriorityQueue print("Queue类实现了一个基本的先进先出(FIFO)容器,使用put ...

  9. RabbitMQ消息队列系列教程(一)认识RabbitMQ

    摘要 RabbitMQ是最为流行的消息中间件,是处理高并发业务的利器.本系列教程,将跟大家一起学习RabbitMQ. 目录 RabbitMQ是什么? RabbitMQ的特点是什么? 一.RabbitM ...

  10. C# Queue与RabbitMQ的爱恨情仇(文末附源码):Q与MQ消息队列简单应用(二)

    上一章我们讲了队列( Queue),这一章我们讲Message Queue消息队列,简称MQ. 定义: MQ是MessageQueue,消息队列的简称(是流行的开源消息队列系统,利用erlang语言开 ...

随机推荐

  1. ansible自定义模板部署apache服务

    使用Ansible来部署Apache服务是一个很好的选择,因为它可以自动化部署过程,确保所有的服务器上都有相同的配置.以下是一个简单的步骤指南,展示如何使用Ansible来部署Apache服务: 1 ...

  2. vue-router单页面应用的多标签页使用问题

    正常的思维 做多vue页面应用,我们的第一反应是配置多个入口点,多个vue应用,编译成多个HTML文件,由服务器来决定路由.这是正常的思维. 但谁知道单页面应用也能做到类似的效果呢.单页面不过是服务器 ...

  3. Typora导出html图片转base64

    Typora 导出html图片转base64 Typora 中图片使用绝对路径 图片路径不要使用中文,否则可能会不成功 打包 jar ,jar放在到出 html 同级目录下 必须要有 jdk 环境 一 ...

  4. vue-cli3 项目路由 history 模式部署到 nginx 服务器

    1.项目修改vue.config.js增加 publicPath: '/' 2.nginx配置 location / {#访问前端页面 root /data/dist;#vue项目存放路径 index ...

  5. 莫烦tensorflow学习记录 (7)循环神经网络 RNN & LSTM

    莫凡大佬的原文章https://mofanpy.com/tutorials/machine-learning/tensorflow/intro-RNN/ RNN 的用途 可以读取数据中的顺序,获取顺序 ...

  6. Java synchronized与ReentrantLock的区别

    synchronized与ReentrantLock的区别 synchronized是一个关键字,ReentrantLock是一个类 synchronized修饰代码块和方法,ReentrantLoc ...

  7. 机器学习笔记(2): Logistic 回归

    Logistic 回归是线性回归中一个很重要的部分. Logistic 函数: \[\sigma(x) = \frac {L} {1 + \exp(-k(x - x_0))} \] 其中: \(L\) ...

  8. CF1838A-Blackboard-List

    题意简述 在黑板上有两个数字,进行如下操作 \(n-2\) 次: 每次在黑板上选择任意两个数,将两个数的差的绝对值写在黑板上. 这样你会得到一个长度为 \(n (3 \le n \le 100)\) ...

  9. 剑指Offer-47.求1+2+3+...+n(C++/Java)

    题目: 求1+2+3+...+n,要求不能使用乘除法.for.while.if.else.switch.case等关键字及条件判断语句(A?B:C). 分析: 利用短路与来判断n是否大于0,从而实现递 ...

  10. P6259

    problem 考虑使用 dfs 模拟. 由于一个程序可能在不进入无限循环的情况下运行很多步,这将会非常缓慢.因此,接下来要加速模拟,可以用记忆化搜索. 在网格中,机器人的可能状态(位置和朝向)只有 ...