PHP+RabbitMQ实现消息队列的完整代码


Posted in PHP onMarch 20, 2019

前言

为什么使用RabbitMq而不是ActiveMq或者RocketMq?

首先,从业务上来讲,我并不要求消息的100%接受率,并且,我需要结合php开发,RabbitMq相较RocketMq,延迟较低(微妙级)。至于ActiveMq,貌似问题较多。RabbitMq对各种语言的支持较好,所以选择RabbitMq。

先安装PHP对应的RabbitMQ,这里用的是 php_amqp 不同的扩展实现方式会有细微的差异.

php扩展地址: http://pecl.php.net/package/amqp

具体以官网为准  http://www.rabbitmq.com/getstarted.html

介绍

  • config.php 配置信息
  • BaseMQ.php MQ基类
  • ProductMQ.php 生产者类
  • ConsumerMQ.php 消费者类
  • Consumer2MQ.php 消费者2(可有多个)

config.php

<?php
 return [
  //配置
  'host' => [
   'host' => '127.0.0.1',
   'port' => '5672',
   'login' => 'guest',
   'password' => 'guest',
   'vhost'=>'/',
  ],
  //交换机
  'exchange'=>'word',
  //路由
  'routes' => [],
 ];

BaseMQ.php

<?php
 /**
  * Created by PhpStorm.
  * User: pc
  * Date: 2018/12/13
  * Time: 14:11
  */
 
 namespace MyObjSummary\rabbitMQ;
 
 /** Member
  *  AMQPChannel
  *  AMQPConnection
  *  AMQPEnvelope
  *  AMQPExchange
  *  AMQPQueue
  * Class BaseMQ
  * @package MyObjSummary\rabbitMQ
  */
 class BaseMQ
 {
  /** MQ Channel
   * @var \AMQPChannel
   */
  public $AMQPChannel ;
 
  /** MQ Link
   * @var \AMQPConnection
   */
  public $AMQPConnection ;
 
  /** MQ Envelope
   * @var \AMQPEnvelope
   */
  public $AMQPEnvelope ;
 
  /** MQ Exchange
   * @var \AMQPExchange
   */
  public $AMQPExchange ;
 
  /** MQ Queue
   * @var \AMQPQueue
   */
  public $AMQPQueue ;
 
  /** conf
   * @var
   */
  public $conf ;
 
  /** exchange
   * @var
   */
  public $exchange ;
 
  /** link
   * BaseMQ constructor.
   * @throws \AMQPConnectionException
   */
  public function __construct()
  {
   $conf = require 'config.php' ;
   if(!$conf)
    throw new \AMQPConnectionException('config error!');
   $this->conf  = $conf['host'] ;
   $this->exchange = $conf['exchange'] ;
   $this->AMQPConnection = new \AMQPConnection($this->conf);
   if (!$this->AMQPConnection->connect())
    throw new \AMQPConnectionException("Cannot connect to the broker!\n");
  }
 
  /**
   * close link
   */
  public function close()
  {
   $this->AMQPConnection->disconnect();
  }
 
  /** Channel
   * @return \AMQPChannel
   * @throws \AMQPConnectionException
   */
  public function channel()
  {
   if(!$this->AMQPChannel) {
    $this->AMQPChannel = new \AMQPChannel($this->AMQPConnection);
   }
   return $this->AMQPChannel;
  }
 
  /** Exchange
   * @return \AMQPExchange
   * @throws \AMQPConnectionException
   * @throws \AMQPExchangeException
   */
  public function exchange()
  {
   if(!$this->AMQPExchange) {
    $this->AMQPExchange = new \AMQPExchange($this->channel());
    $this->AMQPExchange->setName($this->exchange);
   }
   return $this->AMQPExchange ;
  }
 
  /** queue
   * @return \AMQPQueue
   * @throws \AMQPConnectionException
   * @throws \AMQPQueueException
   */
  public function queue()
  {
   if(!$this->AMQPQueue) {
    $this->AMQPQueue = new \AMQPQueue($this->channel());
   }
   return $this->AMQPQueue ;
  }
 
  /** Envelope
   * @return \AMQPEnvelope
   */
  public function envelope()
  {
   if(!$this->AMQPEnvelope) {
    $this->AMQPEnvelope = new \AMQPEnvelope();
   }
   return $this->AMQPEnvelope;
  }
 }

ProductMQ.php

<?php
 //生产者 P
 namespace MyObjSummary\rabbitMQ;
 require 'BaseMQ.php';
 class ProductMQ extends BaseMQ
 {
  private $routes = ['hello','word']; //路由key
 
  /**
   * ProductMQ constructor.
   * @throws \AMQPConnectionException
   */
  public function __construct()
  {
   parent::__construct();
  }
 
  /** 只控制发送成功 不接受消费者是否收到
   * @throws \AMQPChannelException
   * @throws \AMQPConnectionException
   * @throws \AMQPExchangeException
   */
  public function run()
  {
   //频道
   $channel = $this->channel();
   //创建交换机对象
   $ex = $this->exchange();
   //消息内容
   $message = 'product message '.rand(1,99999);
   //开始事务
   $channel->startTransaction();
   $sendEd = true ;
   foreach ($this->routes as $route) {
    $sendEd = $ex->publish($message, $route) ;
    echo "Send Message:".$sendEd."\n";
   }
   if(!$sendEd) {
    $channel->rollbackTransaction();
   }
   $channel->commitTransaction(); //提交事务
   $this->close();
   die ;
  }
 }
 try{
  (new ProductMQ())->run();
 }catch (\Exception $exception){
  var_dump($exception->getMessage()) ;
 }

ConsumerMQ.php

<?php
 //消费者 C
 namespace MyObjSummary\rabbitMQ;
 require 'BaseMQ.php';
 class ConsumerMQ extends BaseMQ
 {
  private $q_name = 'hello'; //队列名
  private $route = 'hello'; //路由key
 
  /**
   * ConsumerMQ constructor.
   * @throws \AMQPConnectionException
   */
  public function __construct()
  {
   parent::__construct();
  }
 
  /** 接受消息 如果终止 重连时会有消息
   * @throws \AMQPChannelException
   * @throws \AMQPConnectionException
   * @throws \AMQPExchangeException
   * @throws \AMQPQueueException
   */
  public function run()
  {
 
   //创建交换机
   $ex = $this->exchange();
   $ex->setType(AMQP_EX_TYPE_DIRECT); //direct类型
   $ex->setFlags(AMQP_DURABLE); //持久化
   //echo "Exchange Status:".$ex->declare()."\n";
 
   //创建队列
   $q = $this->queue();
   //var_dump($q->declare());exit();
   $q->setName($this->q_name);
   $q->setFlags(AMQP_DURABLE); //持久化
   //echo "Message Total:".$q->declareQueue()."\n";
 
   //绑定交换机与队列,并指定路由键
   echo 'Queue Bind: '.$q->bind($this->exchange, $this->route)."\n";
 
   //阻塞模式接收消息
   echo "Message:\n";
   while(True){
    $q->consume(function ($envelope,$queue){
     $msg = $envelope->getBody();
     echo $msg."\n"; //处理消息
     $queue->ack($envelope->getDeliveryTag()); //手动发送ACK应答
    });
    //$q->consume('processMessage', AMQP_AUTOACK); //自动ACK应答
   }
   $this->close();
  }
 }
 try{
  (new ConsumerMQ)->run();
 }catch (\Exception $exception){
  var_dump($exception->getMessage()) ;
 }

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对三水点靠木的支持。

PHP 相关文章推荐
PHP实现根据设备类型自动跳转相应页面的方法
Jul 24 PHP
php实现paypal 授权登录
May 28 PHP
php cli配置文件问题分析
Oct 15 PHP
php如何获取文件的扩展名
Oct 28 PHP
CentOS下与Apache连接的PHP多版本共存方案实现详解
Dec 19 PHP
PHP微信开发之文本自动回复
Jun 23 PHP
thinkphp多表查询两表有重复相同字段的完美解决方法
Sep 22 PHP
php结合md5的加密解密算法实例
Sep 30 PHP
基于php实现的php代码加密解密类完整实例
Oct 12 PHP
PHP文件上传、客户端和服务器端加限制、抓取错误信息、完整步骤解析
Jan 12 PHP
PHP实现关键字搜索后描红功能示例
Jul 03 PHP
PHP连续签到功能实现方法详解
Dec 04 PHP
PHP实现的数据对象映射模式详解
Mar 20 #PHP
PHP单例模式数据库连接类与页面静态化实现方法
Mar 20 #PHP
PHP实现的策略模式示例
Mar 20 #PHP
PHP实现数组和对象的相互转换操作示例
Mar 20 #PHP
Laravel5.4框架使用socialite实现github登录的方法
Mar 20 #PHP
PHP工厂模式的日常使用
Mar 20 #PHP
PHP函数积累总结
Mar 19 #PHP
You might like
php常用字符串处理函数实例分析
2014/11/22 PHP
php+js实现百度地图多点标注的方法
2016/11/30 PHP
PHP实现微信小程序用户授权的工具类示例
2019/03/05 PHP
浅析JavaScript中的常用算法与函数
2013/11/21 Javascript
jQuery实现表格颜色交替显示的方法
2015/03/09 Javascript
JavaScript实现当网页加载完成后执行指定函数的方法
2015/03/21 Javascript
JavaScript判断手机号运营商是移动、联通、电信还是其他(代码简单)
2015/09/25 Javascript
jquery实现具有嵌套功能的选项卡
2016/02/12 Javascript
JavaScript学习笔记之创建对象
2016/03/25 Javascript
浅谈js对象的创建和对6种继承模式的理解和遐想
2016/10/16 Javascript
捕获未处理的Promise错误方法
2017/10/13 Javascript
VUE 直接通过JS 修改html对象的值导致没有更新到数据中解决方法分析
2019/12/02 Javascript
Vue获取页面元素的相对位置的方法示例
2020/02/05 Javascript
在vue中实现嵌套页面(iframe)
2020/07/30 Javascript
vant中的toast轻提示实现代码
2020/11/04 Javascript
Python获取当前时间的方法
2014/01/14 Python
Python ORM框架SQLAlchemy学习笔记之关系映射实例
2014/06/10 Python
python中ConfigParse模块的用法
2014/09/29 Python
如何解决django配置settings时遇到Could not import settings 'conf.local'
2014/11/18 Python
python打开文件并获取文件相关属性的方法
2015/04/23 Python
Python使用defaultdict读取文件各列的方法
2017/05/11 Python
python使用numpy读取、保存txt数据的实例
2018/10/14 Python
Python使用字典实现的简单记事本功能示例
2019/08/15 Python
Python编译为二进制so可执行文件实例
2019/12/23 Python
浅谈图像处理中掩膜(mask)的意义
2020/02/19 Python
python中sklearn的pipeline模块实例详解
2020/05/21 Python
解决python打开https出现certificate verify failed的问题
2020/09/03 Python
班干部演讲稿
2014/04/24 职场文书
彩色的翅膀教学反思
2014/04/25 职场文书
消防志愿者活动方案
2014/08/23 职场文书
合同和协议有什么区别?
2014/10/08 职场文书
公司车辆维修管理制度
2015/08/05 职场文书
MySQL系列之五 视图、存储函数、存储过程、触发器
2021/07/02 MySQL
golang实现浏览器导出excel文件功能
2022/03/25 Golang
Pandas实现DataFrame的简单运算、统计与排序
2022/03/31 Python
利用Python实现翻译HTML中的文本字符串
2022/06/21 Python