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速度全攻略
Oct 09 PHP
PHP 变量定义和变量替换的方法
Jul 30 PHP
phplock(php进程锁) v1.0 beta1
Nov 24 PHP
PHP中实现中文字符进制转换原理分析
Dec 06 PHP
php页面缓存ob系列函数介绍
Oct 18 PHP
php读取二进制流(C语言结构体struct数据文件)的深入解析
Jun 13 PHP
PHP error_log()将错误信息写入一个文件(定义和用法)
Oct 25 PHP
学习php设计模式 php实现抽象工厂模式
Dec 07 PHP
ThinkPHP表单令牌错误的相关解决方法分析
May 20 PHP
php array_merge_recursive 数组合并
Oct 26 PHP
静态html文件执行php语句的方法(推荐)
Nov 21 PHP
如何用PHP实现多线程编程
May 26 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发送AT指令实例代码
2016/05/26 PHP
PHP获取数据库表中的数据插入新的表再原删除数据方法
2018/10/12 PHP
PHP设计模式之组合模式定义与应用示例
2020/02/01 PHP
javascript数字格式化通用类 accounting.js使用
2012/08/24 Javascript
Flexigrid在IE下不显示数据的处理的解决方法
2013/10/24 Javascript
js使用ajax读博客rss示例
2014/05/06 Javascript
js实现点击图片改变页面背景图的方法
2015/02/28 Javascript
javascript弹出拖动窗口
2015/08/11 Javascript
JavaScript缓冲运动实现方法(2则示例)
2016/01/08 Javascript
JS函数arguments数组获得实际传参数个数的实现方法
2016/05/28 Javascript
学习掌握JavaScript中this的使用技巧
2016/08/29 Javascript
详解使用fetch发送post请求时的参数处理
2017/04/05 Javascript
javascript+css3开发打气球小游戏完整代码
2017/11/28 Javascript
js中bool值的转换及“&amp;&amp;”、“||”、 “!!”详解
2017/12/21 Javascript
使用react实现手机号的数据同步显示功能的示例代码
2018/04/03 Javascript
js中火星坐标、百度坐标、WGS84坐标转换实现方法示例
2020/03/02 Javascript
如何修改Vue打包后文件的接口地址配置的方法
2020/04/22 Javascript
React实现类似淘宝tab居中切换效果的示例代码
2020/06/02 Javascript
Vue路由切换页面不更新问题解决方案
2020/07/10 Javascript
[03:17]DOTA2英雄基础教程 剧毒术士
2013/12/12 DOTA
[50:38]DOTA2-DPC中国联赛 正赛 Phoenix vs CDEC BO3 第二场 3月7日
2021/03/11 DOTA
python连接MySQL、MongoDB、Redis、memcache等数据库的方法
2013/11/15 Python
Python 多进程并发操作中进程池Pool的实例
2017/11/01 Python
Python 新建文件夹与复制文件夹内所有内容的方法
2018/10/27 Python
使用python对多个txt文件中的数据进行筛选的方法
2019/07/10 Python
Python Threading 线程/互斥锁/死锁/GIL锁
2019/07/21 Python
Python hashlib模块加密过程解析
2019/11/05 Python
Python 实现Numpy中找出array中最大值所对应的行和列
2019/11/26 Python
CSS3 Backgrounds属性相关介绍
2011/05/11 HTML / CSS
美国二手奢侈品寄售网站:TheRealReal
2016/10/29 全球购物
Groupon荷兰官方网站:高达70%的折扣
2019/11/01 全球购物
征婚广告词
2014/03/17 职场文书
求职信标题怎么写
2014/05/26 职场文书
对党的十八届四中全会的期盼
2014/10/17 职场文书
党支部培养考察意见
2015/06/02 职场文书
微信小程序用户授权最佳实践指南
2021/05/08 Javascript