安裝amqp擴充並訂閱/發布Demo(PHP版)(五),amqpdemo
本文將介紹在PHP中如何使用RabbitMQ來實現訊息的訂閱和發布。我使用的系統依然是Centos7,為了方便,應用伺服器我使用Docker進行部署,容器環境:centos7+nginx+php5.6。
運行環境,安裝AMQP擴充:
如何安裝Docker我就不說了,網上很多教程非常簡單,如果有現成的php環境可以直接使用。Docker中我使用的鏡像名為webdevops/php-nginx,tag為:centos-7-php56。下載鏡像:
(國際頻寬出口不穩定,可能會下載失敗,重試記次就好了)
docker pull webdevops/php-nginx:centos-7-php56 //下載鏡像docker run -d -p 80:80 --name rabbitmq webdevops/php-nginx:centos-7-php56 //運行容器docker exec -ti rabbitmq /bin/bash //進入容器
進入到容器後檢測下環境是否有相應擴充
cd appvi index.php
剛剛我們在運行容器的時候使用80連接埠,在瀏覽器中輸入http://ip
搜尋下沒有amqp相關的資訊。下面開始安裝amqp擴充。
yum install gcc librabbitmq-devel.x86_64 php56w-devel -ywget http://pecl.php.net/get/amqp-1.4.0.tgztar -zxvf amqp-1.4.0.tgzcd amqp-1.4.0phpize./configure --with-amqpmake && make install
在php.ini中開啟extension=amqp.so 接著重啟php-fpm 或 Web伺服器
vi /etc/php.ini extension=amqp.so
我這裡就直接重啟容器了,如果是宿主機直接安裝php環境直接重啟環境。
exit //退出容器docker restart rabbitmq //重啟容器
再查看phpinfo,amqp擴充已經安裝好了:
publish發布訊息
在/app路徑下建立一個publish.php的檔案
touch publish.phpvi publish.php
以下是PHP代碼,我們先定義好用來發訊息的交換器、隊列、RoutingKey、訊息等變數。
$queueName = 'superrd';$exchangeName = 'superrd';$routeKey = 'superrd';$message = 'Hello World!';
按照我們第二章講到的首先建立一個串連。
$connection = new AMQPConnection(array('host' => '10.99.121.137', 'port' => '5672', 'vhost' => '/', 'login' => 'superrd', 'password' => 'superrd'));$connection->connect() or die("Cannot connect to the broker!\n");
建立一個通道。
$channel = new AMQPChannel($connection);
建立一個交換器Exchange,並定義屬性,第二章我們講過有四種類型的交換器,這裡使用直連型DIRECT。AMQP_DURABLE代表這是一個持久化的交換器,不會以為伺服器異常等因素丟失。
$exchange = new AMQPExchange($channel);$exchange->setName($exchangeName);$exchange->setType(AMQP_EX_TYPE_DIRECT);$exchange->setFlags(AMQP_DURABLE);$exchange->declareExchange();
建立一個隊列Queue,前面也講過生產者將訊息發送到Exchange中,Exchange會根據綁定關係投遞到隊列,也就是如果生產者在生產訊息時沒有隊列與之綁定訊息就會丟失。為了保證系統更加健碩,一般無論是訊息的生產者還是消費者都會建立一遍Exchange和Queue,建立後屬性不會改變。同樣AMQP_DURABLE代表這是一個持久化的隊列,隊列會被寫入磁碟。需要注意的是雖然訊息是緩衝在隊列中,但是並不是隊列是持久化的隊列隊列中的訊息就是持久化的,訊息的持久化需要單獨設定。
$queue = new AMQPQueue($channel);$queue->setName($queueName);$queue->setFlags(AMQP_DURABLE);$queue->declareQueue();
通過routeKey綁定交換器和隊列。
$queue->bind($exchangeName, $routeKey);
好了,下面可以發送訊息了
$exchange->publish($message,$routeKey);
如果你希望訊息也是持久化的可以使用如下的代碼,實際測試結果在持久化訊息後訊息發布的效能下降一倍,我的磁碟是pcie的固態硬碟,如果你是機械磁碟這個效能下降估計會更明顯,24核心CPU,48GB記憶體,pcie固態硬碟,單線程的情況下每秒發行就緒2.5萬左右的非持久化訊息,持久化之後變為變為1.2萬左右。
$exchange->publish($message,$routeKey,AMQP_NOPARAM, array('delivery_mode'=>2));
中斷連線。
$connection->disconnect();
同樣在發布訊息之後可以通過WEB工具來查看是否發布成功,
查看交換器多了一個superid交換器。
查看交換器已經有superrd隊列。
點擊隊列查看隊列詳情。Bindings標籤可以看到交換器和隊列的綁定關係。
點擊Get messages標籤Get message(s)按鈕可以看到隊列中的訊息。
到此說明我們已經將一個訊息發布到了訊息佇列中。完整的PHP代碼如下。
'10.99.121.137', 'port' => '5672', 'vhost' => '/', 'login' => 'superrd', 'password' => 'superrd'));$connection->connect() or die("Cannot connect to the broker!\n");try { $channel = new AMQPChannel($connection); $exchange = new AMQPExchange($channel); $exchange->setName($exchangeName); $exchange->setType(AMQP_EX_TYPE_DIRECT); $exchange->setFlags(AMQP_DURABLE); $exchange->declareExchange(); $queue = new AMQPQueue($channel); $queue->setName($queueName); $queue->setFlags(AMQP_DURABLE); $queue->declareQueue(); $queue->bind($exchangeName, $routeKey); $exchange->publish($message,$routeKey); var_dump("[x] Sent 'Hello World!'");} catch (AMQPConnectionException $e) { var_dump($e); exit();} $connection->disconnect();
Subscribe訂閱訊息
在/app路徑下建立一個subscribe.php的檔案
touch subscribe.phpvi subscribe.php
以下是PHP代碼,和發布訊息一樣我們先定義好用交換器、隊列、RoutingKey等變數。
$queueName = 'superrd';$exchangeName = 'superrd';$routeKey = 'superrd';
按照我們第二章講到的首先建立一個串連。
$connection = new AMQPConnection(array('host' => '10.99.121.137', 'port' => '5672', 'vhost' => '/', 'login' => 'superrd', 'password' => 'superrd'));$connection->connect() or die("Cannot connect to the broker!\n");
建立一個通道。
$channel = new AMQPChannel($connection);
與發布訊息一樣建立交換器。
$exchange = new AMQPExchange($channel);$exchange->setName($exchangeName);$exchange->setType(AMQP_EX_TYPE_DIRECT);$exchange->setFlags(AMQP_DURABLE);$exchange->declareExchange();
建立一個隊列Queue。
$queue = new AMQPQueue($channel);$queue->setName($queueName);$queue->setFlags(AMQP_DURABLE);$queue->declareQueue();
通過routeKey綁定交換器和隊列。
$queue->bind($exchangeName, $routeKey);
重點來了,阻塞訂閱訊息。
//阻塞模式接收訊息echo "Message:\n";while(True){ $queue->consume('processMessage');//自動ACK應答 //$queue->consume('processMessage', AMQP_AUTOACK); }$conn->disconnect();/** 消費回呼函數* 處理訊息*/function processMessage($envelope, $q) { $msg = $envelope->getBody(); echo $msg."\n"; //處理訊息 $q->ack($envelope->getDeliveryTag()); //手動發送ACK應答}
注意因為是阻塞監聽,因為輸出緩衝區的原因用瀏覽器訪問該檔案是看不到輸出的。使用指令碼訪問。
php /app/subscribe.php
通過WEB工具查看隊列。superrd隊列中的訊息數已經為0。
完整的PHP代碼如下。
'10.99.121.137', 'port' => '5672', 'vhost' => '/', 'login' => 'superrd', 'password' => 'superrd'));$connection->connect() or die("Cannot connect to the broker!\n");$channel = new AMQPChannel($connection);$exchange = new AMQPExchange($channel);$exchange->setName($exchangeName);$exchange->setType(AMQP_EX_TYPE_DIRECT);$exchange->setFlags(AMQP_DURABLE);$exchange->declareExchange();$queue = new AMQPQueue($channel);$queue->setName($queueName);$queue->setFlags(AMQP_DURABLE);$queue->declareQueue();$queue->bind($exchangeName, $routeKey);//阻塞模式接收訊息echo "Message:\n";while(True){ $queue->consume('processMessage');//自動ACK應答 //$queue->consume('processMessage', AMQP_AUTOACK);}$conn->disconnect();/** 消費回呼函數* 處理訊息*/function processMessage($envelope, $q) { $msg = $envelope->getBody(); echo $msg."\n"; //處理訊息 $q->ack($envelope->getDeliveryTag()); //手動發送ACK應答}