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 相关文章推荐
如何删除多级目录
Oct 09 PHP
一个用php实现的获取URL信息的类
Jan 02 PHP
php循环检测目录是否存在并创建(循环创建目录)
Jan 06 PHP
PHP session有效期session.gc_maxlifetime
Apr 20 PHP
windows服务器中检测PHP SSL是否开启以及开启SSL的方法
Apr 25 PHP
destoon常用的安全设置概述
Jun 21 PHP
PHP源码分析之变量的存储过程分解
Jul 03 PHP
PHP图片处理之使用imagecopyresampled函数裁剪图片例子
Nov 19 PHP
php目录遍历函数opendir用法实例
Nov 20 PHP
php 使用array函数实现分页
Feb 13 PHP
php在apache环境下实现gzip配置方法
Apr 02 PHP
Yii2配置Nginx伪静态的方法
May 05 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中GET变量的使用
2006/10/09 PHP
精美漂亮的php分页类代码
2013/04/02 PHP
探讨如何在PHP开启gzip页面压缩实例
2013/06/09 PHP
一组PHP加密解密函数分享
2014/06/05 PHP
成为好程序员必须避免的5个坏习惯
2014/07/04 PHP
PHP CURL 内存泄露问题解决方法
2015/02/12 PHP
php上传大文件设置方法
2016/04/14 PHP
js页面跳转的问题(跳转到父页面、最外层页面、本页面)
2013/08/14 Javascript
jQuery中delegate与on的用法与区别示例介绍
2013/12/20 Javascript
原生js仿jq判断当前浏览器是否为ie,精确到ie6~8
2014/08/30 Javascript
angularjs指令中的compile与link函数详解
2014/12/06 Javascript
jQuery的观察者模式详解
2014/12/22 Javascript
JavaScript设计模式之工厂模式和构造器模式
2015/02/11 Javascript
javascript关于继承解析
2016/05/10 Javascript
JS正则截取两个字符串之间及字符串前后内容的方法
2017/01/06 Javascript
bootstrap手风琴折叠示例代码分享
2017/05/22 Javascript
微信小程序实现自定义picker选择器弹窗内容
2020/05/26 Javascript
Vue 实现手动刷新组件的方法
2019/02/19 Javascript
vue子路由跳转实现tab选项卡
2019/07/24 Javascript
Node.js web 应用如何封装到Docker容器中
2020/09/01 Javascript
Python之eval()函数危险性浅析
2014/07/03 Python
python模拟表单提交登录图书馆
2018/04/27 Python
python中pip的安装与使用教程
2018/08/10 Python
python3 tkinter实现添加图片和文本
2019/11/26 Python
Python: tkinter窗口屏幕居中,设置窗口最大,最小尺寸实例
2020/03/04 Python
查看jupyter notebook每个单元格运行时间实例
2020/04/22 Python
css3的@media属性实现页面响应式布局示例代码
2014/02/10 HTML / CSS
法国美发器材和产品购物网站:Beauty Coiffure
2016/12/05 全球购物
澳大利亚在线奢侈品时尚零售平台:Azura Runway
2021/01/13 全球购物
团队精神演讲稿
2013/12/31 职场文书
社区服务活动总结
2014/05/07 职场文书
优质服务演讲稿
2014/05/14 职场文书
2014年国庆节寄语
2014/09/19 职场文书
单位综合评价意见
2015/06/05 职场文书
2019公司管理制度
2019/04/19 职场文书
Python中的 enumerate和zip详情
2022/05/30 Python