消费信息如下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. QT中各控件的属性和方法

    1.在QT6中,QLabel类具有许多属性和方法,以下是QLabel类的常见属性和调用方法:setText(const QString &text):设置标签的文本内容.setAlignmen ...

  2. k8s错误集合

    1.etcd没有启动的 [root@mcwk8s03 ~]# kubectl get nodesUnable to connect to the server: context deadline ex ...

  3. 解决input中输入中文过程中会触发input事件的问题

    问题描述: 监听文本输入框的input事件,在拼写汉字时会触发input事件,如下图: 需求: 选词完成后触发input事件,只触发一次. 解决办法: 通过查阅资料得知在输入中文(包括语音识别时)会先 ...

  4. 《剑指offer3- 从末尾到头打印链表》

    题目描述 输入一个链表,按链表值从尾到头的顺序返回一个ArrayList.   本质上是逆转链表   /** * struct ListNode { * int val; * struct ListN ...

  5. 我用docker搭建的第一个博客

    其实很早就听说了docker这个东西,一直以来想玩不知道拿什么下手,再加上前段时间听了一个思科的年度网络报告讲解里面稍微提了一下docker的优势以及网络即服务的概念.想通了,不是每一步都得亲历亲为, ...

  6. itestwork(爱测试)开源一站式接口测试&敏捷测试工作站 9.0.0 GA 发布,重大升级

    (一)itest 简介 itest work (爱测试)  一站式工作站让测试变得简单.敏捷.itest work 包含极简的任务管理,测试管理,缺陷管理,测试环境管理,接口测试,接口Mock 6合1 ...

  7. Java synchronized与ReentrantLock的区别

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

  8. Java异常中throw 与throws的区别

    throw 与 throws区别 在Java中,throws和throw是两个不同的关键字,它们在异常处理中起着不同的作用. throws关键字: throws用于声明一个方法可能会抛出的异常.当一个 ...

  9. LeetCode 715. Range Module Range 模块 (Java)

    题目: A Range Module is a module that tracks ranges of numbers. Your task is to design and implement t ...

  10. 开启安全功能 ES 集群就安全了吗?

    背景 经常跟 ES 打交道的朋友都知道,现在主流的 ES 集群安全方案是:RBAC + TLS for Internal + HTTPS . 作为终端用户一般只需要关心用户名和密码就行了.作为管理和运 ...