RabbitMQの実装のAMQPプロトコル(アドバンスト・メッセージキュープロトコル)。
RabbitMQのの私の理解に基づきました:
本質的になる構造パブリッシャ(プロデューサー)、交換機(スイッチ)、キュー(メッセージキュー)、消費者(顧客):
はじめに、それぞれのデータ構造:
出版社(メーカー):メッセージのプロデューサとして、メッセージキューに格納されたメッセージを生成し、製造プロセスは、商品の製造業者出荷あります。
交換機(スイッチ):ディスパッチャメッセージは、メッセージが最初に通過する、商品の種類によってディスパッチャは異なる自動販売機に投入されます。
キュー(メッセージキュー):メッセージリポジトリ、自動販売機。
消費者(消費者):消費者のメッセージ、保管倉庫からメッセージを削除し、消費のプロセスは、人々が自動販売機から購入しています。
一般的な交換タイプのトピック、ヘッダ、直接、ファンアウト。
補足概念:
メッセージの確認応答メカニズム:、メッセージの両側相互作用送信者は(処理が完了したところ、メッセージが問題ではない)受信者のニーズはメッセージが受信された消費者にフィードバックされる、メッセージの後に送信されます、そしてインタラクティブAMQPパーティーにも確実にするために、このメカニズムを必要とされます実際に(メッセージを受信したメッセージを受信した後、受信者が、肯定応答パケットの戻りがACK必要としないので、双方向の相互作用は、もはや必ずしも無意味な重複確認応答、即ち、もはや送信者はない受け取る場合、ネットワーク遅延が発生検討されているのでACKパケット)、メッセージが実際に受信者によって受信されたことを保証するために、メッセージは、除去倉庫であることができます。残念ながら、あなたは本当に商品販売される前に、自動販売機、支払わなければならないこと、たとえを再生するとき。
デフォルトの交換:プロデューサが交換を指定しない場合、メッセージは、割り当てルール、デフォルトリガンド交換機に送信されるデフォルト交換は、指定されたキューに応じてキューにキューにメッセージを送信します。
(MQ Iパッケージ ``の生産と消費に行われますが、高可用性を実現しませんでした、ビジネス・ロジックの処理にシフト注意にユーザーを可能にします)
ここでは、コード、ディレクトリ構造は次のとおりです。
/ Mqを/ ABS抽象化層
/ Mqを/ OBJ具現層
/ Mqを/ configに設定
/ Mqを/ Webアプリケーション層(デモ)
/mq/abs/MqclientObject.php
<?php
namespace mq\abs;
use \PhpAmqpLib\Connection as MQC;
use \PhpAmqpLib\Exception\AMQPHeartbeatMissedException;
abstract class MqClientObject
{
public $channel;
private static $connect;
private static $config;
private static $lastConnectTime;
public function __construct(array $config)
{
if(!(self::$connect instanceof MQC\AMQPStreamConnection)) {
self::connect($config);
}
if(!self::$config) {
self::$config = $config;
}
$this->channel = self::$connect->channel();
}
private static function connect(array $config)
{
self::$connect = new MQC\AMQPStreamConnection(
$config['host'],
$config['port'],
$config['user'],
$config['password'],
isset($config['vhost']) && !empty($config['vhost']) ? $config['vhost'] : '/'
);
self::$lastConnectTime = time();
}
public static function close()
{
try{
self::$connect->close();
self::$connect = null;
self::$config = null;
} catch (\Exception $ex) {
return false;
}
return true;
}
public function createTempQueue()
{
list($queue, ) = $this->channel->queue_declare("", false, false, true, false);
return $queue;
}
public function ping()
{
try{
self::$connect->checkHeartBeat();
} catch (AMQPHeartbeatMissedException $MQheartEx) {
return false;
} catch(\Exception $ex) {
//todo log
exit(0);
}
return true;
}
public function reConnect()
{
self::connect(self::$config);
}
}
/mq/abs/MqconsumerObject.php
<?php
namespace mq\abs;
abstract class MqConsumerObject extends MqClientObject
{
public $queue;
private $blocking = true;
private $qos = true;
private $ack = false;
private $qosCount = 1;
public function setQueue($queue)
{
$this->queue = $queue;
return $this;
}
public function disableAck()
{
$this->ack = true;
}
public function disablePos()
{
$this->qos = false;
}
public function setQosCount($count)
{
$this->qosCount = $count;
}
public function disableBlocking()
{
$this->blocking = false;
}
//默认的消费方式
public function consume($failClose = false)
{
if($this->qos) {
$this->channel->basic_qos(null, $this->qosCount, null);
}
$this->channel->basic_consume(
$this->queue,
'',
false,
$this->ack,
false,
false,
[$this, 'call']
);
while(count($this->channel->callbacks)) {
$this->channel->wait();
if(!$this->blocking) {
$this->channel->close();
}
}
}
//回调函数
public function call($event)
{
$message = $event->body;
$channel = $event->delivery_info['channel'];
if($this->run($message)) {
$channel->basic_ack($event->delivery_info['delivery_tag']);
}
}
public function closeChannel()
{
try{
$this->channel->close();
$this->channel = null;
} catch (\Exception $ex) {
return false;
}
return true;
}
//业务处理
public abstract function run($message);
public function __destruct()
{
if($this->channel != null) {
$this->closeChannel();
}
}
}
/mq/abs/MqPublisherObject.php
<?php
namespace mq\abs;
abstract class MqPublisherObject extends MqClientObject
{
public $exchange;
public $bindKey;
public $queue;
public function setExchange($exchange)
{
$this->exchange = $exchange;
return $this;
}
public function setBindKey($bindKey)
{
$this->bindKey = $bindKey;
return $this;
}
public function setQueue($queue)
{
$this->queue = $queue;
return $this;
}
public abstract function bind();
public abstract function publish($message, $config = null);
}
/ MQ /設定/ mq_config
<?php
define('MQ_CONFIG', [
'host' => '127.0.0.1',
'port' => 5672,
'user' => 'dora',
'password' => 'hopeforyou',
'vhost' => '/dora'
]);
/mq/obj/DirectPublisherObject.php
<?php
namespace mq\obj;
use \mq\abs as MA;
use \PhpAmqpLib\Message as PM;
class DirectPublisherObject extends MA\MqPublisherObject
{
public function bind()
{
$this->channel->queue_bind($this->queue, $this->exchange, $this->bindKey);
}
public function publish($message, $config = null)
{
$objMessage = new PM\AMQPMessage($message);
$this->channel->basic_publish($objMessage, $this->exchange, $this->bindKey);
}
}
/mq/obj/FanoutPublisherObject.php
<?php
namespace mq\obj;
use \mq\abs as MA;
use \PhpAmqpLib\Message as PM;
class FanoutPublisherObject extends MA\MqPublisherObject
{
public function bind()
{
$this->channel->queue_bind($this->queue, $this->exchange);
}
public function publish($message, $config = null)
{
//暂不支持$config配置
$objMessage = new PM\AMQPMessage($message);
$this->channel->basic_publish($objMessage, $this->exchange);
}
}
/mq/obj/TopicsPublisherObject.php
<?php
namespace mq\obj;
use \mq\abs as MA;
use \PhpAmqpLib\Message as PM;
class TopicsPublisherObject extends MA\MqPublisherObject
{
public function bind()
{
$this->channel->bind_queue($this->queue, $this->exchange, $this->bindKey);
}
public function publish($message, $config = null)
{
$objMessage = new PM\AMQPMessage($message);
$this->channel->basic_publish($objMessage, $this->exchange, $this->bindKey);
}
}
/mq/obj/PayCallbackConsumer.php
<?php
namespace mq\obj;
use mq\abs\MqConsumerObject;
class PayCallbackConsumer extends MqConsumerObject
{
public function run($message)
{
//todo 业务逻辑代码
//消费者消费一次完毕后就不再消费
// $this->disableBlocking();
//return true 代表消息处理完毕
//return false 代表消息处理异常,不正真消费
}
}
/mq/web/index.phpテストコード
<?php
define('APP_PATH', dirname(__DIR__));
require APP_PATH.'/vendor/autoload.php'; //注册自动加载函数列表
require APP_PATH.'/config/mq_config.php'; //mq注册常量
//use \mq\obj as MO;
//将$queue绑定到exchange dora.fanout上
//$objMq = new MO\FanoutPublisherObject(MQ_CONFIG);
////交换机绑定队列
////$queue = 'dora.hope.for.you';
////$objMq->setExchange('dora.fanout')->setQueue($queue)->bind();
////向交换机发送消息
//$objMq->setExchange('dora.fanout');
//$objMq->publish('hope for you!');
//将$queue绑定到exchange dora.direct上
//$objMq = new MO\DirectPublisherObject(MQ_CONFIG);
//$bindKey = 'hope';
//交换机绑定队列
//$queue = 'dora.direct.hope.for';
//$objMq->setExchange('dora.direct')->setBindKey($bindKey)->setQueue($queue)->bind();
//向交换机发送消息
//$objMq->setExchange('dora.direct')->setBindKey($bindKey);
//$objMq->publish('hope for you!');
//将$queue绑定到exchange dora.topic上
//$objMq = new MO\DirectPublisherObject(MQ_CONFIG);
//$bindKey = 'hope.for';
//交换机绑定队列
//$queue = 'dora.topic.hope.for';
//$objMq->setExchange('dora.topic')->setBindKey($bindKey)->setQueue($queue)->bind();
//向交换机发送消息
//$objMq->setExchange('dora.topic')->setBindKey($bindKey);
//$objMq->publish('hope for you!');
//消费队列
//$objConsumer = new MO\PayCallbackConsumer(MQ_CONFIG);
//$queue = 'dora.hope.for.you';
//$objConsumer->setQueue($queue)->consume();
メッセージがメッセージキューにアップロードされたユーザーは、唯一のルートをルーティング、交換に使用されるスイッチを心配する必要があります。(実際の項目とコードまたはスイッチによって)一時的なキューを除いて(キューを作成しません)。
消費者のUserキューは、唯一継承する必要MqconsumerObjectクラスと実装のメッセージを処理するために、runメソッド、;
参考: