thinkphp5 使用 RabbitMQ代码示例,amqp扩展非php-amqplib

本文所使用的是PHP的amqp扩展,不是composer安装的php-amqplib

一、在控制器里封装了一个基类–生产者

<?php
namespace app\home\controller;

/**
 * RabbitMQ 基类
 * 直连模式
 */
class RabbitMqController
{
    private $conn;
    private $channel;
    private $ex;
    private $queue;
    private $routingKey;
    public function __construct($exchangeName,$queueName,$routingKey)
    {

        $this->exchangeName = $exchangeName;
        $this->queueName = $queueName;
        $this->routingKey = $routingKey;
        $this->conf = [
            'host' => '127.0.0.1',
            'port' => 5672,
            'login' => 'guest', //改为自己RabbitMQ账号
            'password' => 'guest', //改为自己RabbitMQ密码
        ];

        //  1、创建链接对象
        $this->conn = new \AMQPConnection($this->conf);
        if (!$this->conn->connect()) {
            echo json(["st" => 505, "errMsg" => "Cannot connect to the rabbitMQ"]);
            die();
        }

        //  2、创建通道
        $this->channel = new \AMQPChannel($this->conn);
        $this->channel->qos(0,2);
        //  3、创建交换机
        $this->ex = new \AMQPExchange($this->channel);
        //  4、设置交换机名称
        $this->ex->setName($this->exchangeName);
        //  5、设置交换机的类型
        $this->ex->setType(AMQP_EX_TYPE_DIRECT);
        //  6、设置交换机持久化
        $this->ex->setFlags(AMQP_DURABLE);
        //  7、声明交换机
        $this->ex->declareExchange();

        //  8、创建消息队列
        $this->queue = new \AMQPQueue($this->channel);
        //  9、设置消息队列的名称
        $this->queue->setName($this->queueName);
        //  10、设置消息队列持久化(消息要想持久化,交换机和消息队列必须要持久化)
        $this->queue->setFlags(AMQP_DURABLE);
        //  11、声明消息队列
        $this->queue->declareQueue();
        //  12、绑定交换机和路由键
        $this->queue->bind($this->exchangeName, $this->routingKey);

    }

    public function ping(){
        die('pone');
    }

    /**
     * @param $msg array 消息内容
     * @throws AMQPChannelException
     * @throws AMQPConnectionException
     * @throws AMQPExchangeException
     *
     * @return bool TRUE on success or FALSE on failure.
     */
    public function sendMsg($msg){
        $msgBody = is_array($msg)?json_encode($msg):$msg;
        return $this->ex->publish($msgBody,$this->routingKey,AMQP_NOPARAM,array('delivery_mode' => 2));
    }
}

二、在控制器里封装了一个基类–消费者

class RabbitMqConsumerController
{
    private $conn;
    private $channel;
    private $queue;
    private $routingKey;
    public function __construct($exchangeName,$queueName,$routingKey)
    {

        $this->exchangeName = $exchangeName;
        $this->queueName = $queueName;
        $this->routingKey = $routingKey;
        $this->conf = [
            'host' => '127.0.0.1', //部署时,修改为自己RabbitMQ服务器地址
            'port' => 5672,
            'login' => 'guest', //改为自己RabbitMQ账号
            'password' => 'guest', //改为自己RabbitMQ密码
            'heartbeat'=> 600, //心跳,主要是给消费者使用
        ];

        //  1、创建链接对象
        $this->conn = new \AMQPConnection($this->conf);
        if (!$this->conn->connect()) {
            echo json(["st" => 505, "errMsg" => "Cannot connect to the rabbitMQ"]);
            die();
        }

        //  2、创建通道
        $this->channel = new \AMQPChannel($this->conn);
        $this->channel->qos(0,2); //消息预取,此处设置为2 表示只有两条消息可先发送给消费者,后续新消息在队列里等待消费者消费完再发送,防止消息过多,消费者压力过大发生异常

        //  3、创建消息队列
        $this->queue = new \AMQPQueue($this->channel);
        $this->queue->setName($this->queueName); //  设置消息队列的名称
        $this->queue->setFlags(AMQP_DURABLE); //  设置消息队列持久化(消息要想持久化,交换机和消息队列必须要持久化)
        $this->queue->declareQueue(); //  声明消息队列

        //  4、绑定交换机和路由键
        $this->queue->bind($this->exchangeName, $this->routingKey);

    }

    public function ping(){
        die('pone');
    }

    /**
     * @param $parma array [$message,"processMessage"]
     * $message为Message的对象,processMessage为Message的方法
     * 调用该方法需要用php的cli模式
     * @throws AMQPChannelException
     * @throws AMQPConnectionException
     * @throws AMQPEnvelopeException
     */
    public function consume($parma){
        // 阻塞
        while(True){
            $this->queue->consume($parma);
        }
    }
}

三、生产者:

<?php

namespace app\home\controller;
use think\db;

/**
 * 消费者写入消息
 */
class MqController{

    public $code = "test";

    /**
     * 消息写入
     */
    public function pub() {
    	//业务需求,给每个消息创建了一个唯一key, 然后将消息+key写入mysql库。
    	$msgData['type'] = 'SendEmail';  //每种信息都有一个类型
        $msgData['unique_key'] = date('YmdHis').mt_rand (1000,9999);
		$msgData['info'] = 'test';
        if($this->insertData($msgData)){
            $mq = new RabbitMqController($this->code,$this->code,$this->code); //交换机、队列名、路由键我这里用的是一个变量
            $mq->sendMsg($msgData); //发送消息到RabbitMQ服务器
        }

        $resultData['code'] = 1;
        $resultData['unique_key'] = $msgData['unique_key'];
        $resultData['msg'] = '消息已写入';
        return json($resultData);
    }

    //消息入库
    public function insertData($data){
        if(isset($data['type']) && isset($data['unique_key'])){
            if(!empty($data['type']) && !empty($data['unique_key'])){
                $insertData['type'] = $data['type'];
                $insertData['unique_key'] = $data['unique_key'];
                $insertData['msg_data'] = json_encode($data);
                $res = Db::name('mq_info')->insert($insertData);
                if($res){
                    return true;
                }
            }
        }
        return false;
    }
}

四、消费者:

<?php

namespace app\home\controller;
use think\Db;

/**
 * 消息队列消费者
 * 部署:
 * PHP环境部署需要安装RabbitMQ扩展 http://pecl.php.net/package/amqp (选择PHP对应的版本扩展);PHP配置文件,加入 extension=php_amqp.dll
 * 配置php环境变量;切换到项目public目录cmd `php index.php zoneking_dept/sync_mq_consumer/receiveMsg`
 */
class MqConsumerController {

    function processMessage($envelope, $queue) {
        $msg = json_decode($envelope->getBody(),true);
        echo 'message:'. PHP_EOL;
        var_dump($msg); //打印接收到的消息
        echo PHP_EOL;
		try{
			if(!empty($msg['type']) && !empty($msg['unique_key'])){
            	$res = false;
            	switch ($msg['type']){
                	case 'SendEmail':
                    $res = $this->toSend($msg); //处理消息,业务操作...
                    break;
            	}
            	if($res){
                	$queue->ack($envelope->getDeliveryTag()); //手动 ack
                	echo 'message deal ok'. PHP_EOL;
            	}
           	}
		}catch (\Throwable $e){//Throwable是PHP7中可以用作任何对象抛出声明的基本接口,包括 Expection 异常和 Error 错误。
			$queue->ack($envelope->getDeliveryTag());

            $updateData['deal_data'] = 'message discarded!!!!'.$e->getMessage();
            $this->updateData($msg['type'],$msg['unique_key'],$updateData);
            echo 'message discarded!!!!'.$e->getMessage(). PHP_EOL;
		}
        
    }

    public function receiveMsg()
    {
        try{
            $mq = new RabbitMqConsumerController($this->code,$this->code,$this->code);
            echo 'Connected to the rabbitMQ'. PHP_EOL;
            $message = new SyncMqConsumerController();
            $mq->consume([$message,"processMessage"]);
        }catch (\Throwable $e){ //如果连接不到RabbitMQ服务器,则捕获异常,启动重连机制
            echo 'Cannot connect to the rabbitMQ'. PHP_EOL;
            echo $e->getMessage();
            echo PHP_EOL;
            while (true) //每60秒重试
            {
                echo 'Try reconnect...'. PHP_EOL;
                sleep(60);
                $this->receiveMsg();
                break;
            }
        }

    }

    /**
     * 发送邮箱信息
     */
    public function toSend($msg) {
        ...
        $updateData['deal_data'] = '处理完毕!';
        $this->updateData($msg['type'],$msg['unique_key'],$updateData);
        return true;

    }

	//消费者
    public function updateData($type,$unique_key,$updateData){
        if(!empty($type) && !empty($unique_key)){
            $map['type'] = $type;
            $map['unique_key'] = $unique_key;

            $updateData['deal_ok'] = 'true';
            $res = Db::name('mq_info')->where($map)->update($updateData);
            if($res){
                return true;
            }
        }
        return false;
    }

}

消费信息mysql存储

1. 如何启动消费者?
配置php环境变量;切换到项目public目录cmd php index.php zoneking_dept/sync_mq_consumer/receiveMsg

2. 消费者一段时间没有消息处理,就会出现卡死现象,再有新消息不会自动处理问题?
给消费者设置一个心跳,定时发送心跳告知服务器自己还“活着”,

$this->conf = [
   	 ...
    'heartbeat'=> 10, //心跳,主要是给消费者使用,这里重点
];

$this->conn = new \AMQPConnection($this->conf);

3. 服务器关闭后,消费者连接抛异常,等服务器再打开,消费者不会重新进入工作?
给消费者加上重试机制,当连接不到服务器就每隔一段时间进行重新连接,直到连接上为止。重点代码:

try{
            $mq = new RabbitMqController($this->center_code,$this->center_code,$this->center_code);
            echo 'Connected to the rabbitMQ'. PHP_EOL;
            $message = new SyncMqConsumerController();
            $mq->consume([$message,"processMessage"]);
        }catch (\Exception $e){ //如果连接不到RabbitMQ服务器,则捕获异常,启动重连机制
            echo 'Cannot connect to the rabbitMQ'. PHP_EOL;
            echo $e->getMessage();
            echo PHP_EOL;
            while (true) //每60秒重试
            {
                echo 'Try reconnect...'. PHP_EOL;
                sleep(60);
                $this->receiveMsg();
                break;
            }
        }

4. 消费者加上了心跳机制,但是不管用?
我们可以登录管理面板查看是否启用了心跳机制
在这里插入图片描述
如果 Heartbeat 为空则说明没有启动心跳。但是代码里明明配置上了,为什么不起作用呢?这个问题一直困扰了我好久。
主要问题在于你安装的 amqp扩展 版本支不支持心跳,你在 phpinfo() 里可以查看到
在这里插入图片描述
有的低版本的扩展不支持,当你使用php7 时,对应的windows扩展,(注意此处是windows)才支持心跳,于是我升级了PHP版本,下载了对应的扩展安装,问题解决。
扩展下载地址 http://pecl.php.net/package/amqp (选择PHP对应的版本扩展);PHP配置文件,加入 extension=php_amqp.dll

5. 工作模式?
如上代码的消费者可以开启工作模式,即可以有多个消费者同时分摊队列中的消息,我们只需开启多个cmd窗口:
切换到项目public目录cmd php index.php zoneking_dept/sync_mq_consumer/receiveMsg

6. 其他模式

参考:http://www.hangdaowangluo.com/archives/1337
文章底部有相关阅读
在这里插入图片描述

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: ThinkPHP6是一个基于PHP的开源框架,是国内使用最为广泛的一种框架之一。而RabbitMQ是一个流行的消息队列中间件,广泛用于大规模分布式系统中的消息传递。那么,在ThinkPHP6中使用RabbitMQ主要有以下几个方面的应用。 首先,ThinkPHP6可以很方便地集成RabbitMQ,通过RabbitMQAMQP协议进行消息的发送与接收。开发者可以使用ThinkPHP6提供的消息队列服务提供者,调用RabbitMQ的相关方法,实现应用程序与消息队列之间的交互。这样可以有效地解耦消息的生产者与消费者,实现并行处理,提高应用的性能和可伸缩性。 其次,ThinkPHP6可以使用RabbitMQ来实现任务调度与消息通知。可以将一些耗时较长的任务放入消息队列中,后台异步执行,从而提高系统的响应速度。同时,也可以通过RabbitMQ发送通知消息,实现系统之间的实时通信,提供更好的用户体验。 另外,ThinkPHP6还可以利用RabbitMQ实现分布式系统的日志处理。可以将应用程序的日志信息发送到RabbitMQ的消息队列中,通过消费者来处理这些日志。这样可以将日志的收集、存储和处理工作分布到不同的节点上,提高系统的日志处理效率和可靠性。 总结来说,ThinkPHP6使用RabbitMQ可以实现消息的发送与接收、任务调度与消息通知,以及分布式系统的日志处理等功能。通过合理地利用RabbitMQ的特性,可以为项目提供更好的解耦、并行处理和可伸缩性,提高系统的性能和用户体验。 ### 回答2: thinkphp6是一个基于PHP的开源框架,而RabbitMQ是一个消息代理和队列服务器。RabbitMQ采用AMQP(高级消息队列协议)来传递消息,它可以在分布式系统中保存和转发消息,使系统之间的通信更加高效和可靠。 在Thinkphp6中使用RabbitMQ可以实现异步消息处理和解耦。通过使用RabbitMQ,我们可以将耗时的任务放入消息队列中进行处理,从而提升应用的性能。例如,可以将发送邮件、短信等耗时的操作放入RabbitMQ中进行处理,避免阻塞应用。 在使用Thinkphp6中结合RabbitMQ时,首先需要安装RabbitMQ并启动服务。然后,在Thinkphp6中引入相关的RabbitMQ扩展包,例如php-amqplib等。接下来,我们可以创建一个RabbitMQ的连接和通道,并声明消息队列。在代码中通过监听消息队列,当有新的消息到达时,可以触发相应的方法进行处理。另外,在Thinkphp6中也可以使用RabbitMQ的交换机和路由机制来实现灵活的消息分发。 使用Thinkphp6和RabbitMQ的好处是可以解决应用性能瓶颈问题,提高应用的响应速度和并发能力。同时,通过将耗时任务放入消息队列中,可以实现任务的异步处理,提升用户体验。另外,RabbitMQ灵活的路由机制也为应用提供了更多的扩展性和灵活性。 总之,结合Thinkphp6和RabbitMQ可以为应用提供高效、稳定的消息传递和处理能力,使应用更加健壮和可靠。 ### 回答3: ThinkPHP 6是一种流行的PHP框架,RabbitMQ是一种消息中间件。这两者之间可以进行集成来实现消息的发布和订阅。 ThinkPHP 6中集成RabbitMQ可以通过使用RabbitMQ的PHP客户端库来实现。首先,需要在项目中引入RabbitMQ的PHP客户端库,可以使用composer来管理依赖。 接下来,可以在ThinkPHP 6的配置文件中配置RabbitMQ的连接信息,包括消息队列的地址、端口、用户名和密码等。这样,就可以通过创建RabbitMQ的连接对象来与消息队列进行交互。 在ThinkPHP 6中,可以使用消息队列的生产者来发布消息,通过调用RabbitMQ的连接对象的相关方法,将消息发布到指定的队列中。而消费者则可以通过监听队列,当有消息到达时,自动触发相应的处理逻辑。 通过将消息发布和订阅的逻辑封装成独立的任务或者事件,在ThinkPHP 6中可以使用任务调度器或者事件监听器来执行相应的操作。这样可以实现异步处理任务和解耦业务逻辑的目的。 总结来说,ThinkPHP 6可以通过与RabbitMQ进行集成,实现消息的发布和订阅。通过配置连接信息、使用RabbitMQ的PHP客户端库和任务调度器或事件监听器,可以达到异步处理任务和解耦业务逻辑的效果。这对于大规模的系统或者高并发场景下的消息处理常有用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

有码无尘

知识无价,有收获就好!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值