PHP 對rabbitMQ的詳細使用講解測試(TP5) 版本三 之 路由篇

rabbitMQ 下載官網 https://www.rabbitmq.com/

PHP鏈接MQ擴展地址 https://github.com/php-amqplib/php-amqplib

或者使用  composer  安裝

 composer require php-amqplib/php-amqplib
 

<?php
/**
 * Created by PhpStorm.
 * User: Json
 * Date: 2020/4/30
 * Time: 14:19
 */
namespace app\index\controller;

use PhpAmqpLib\Connection\AMQPStreamConnection;
use PhpAmqpLib\Message\AMQPMessage;
use think\Controller;

class Route extends Controller{

    // 路由
    // 在發佈、訂閱 新增 路由功能  使他能夠只訂閱消息的一個字集
    //例如 我們只需要把嚴重的錯誤寫入日誌文件 不重要的錯誤 輸出到控制檯中
    //前面的例子 我們已經創建過隊列綁定交換機

    // 還使用日誌寫入作爲例子
    //需要寫入日誌的發送者
    public function log_task($argv){
        $data=$argv;
        if(empty($data)){
            $data="Hello Word";
        }
        //交換機
        //交換機 (Exchanges)
        //我們發送消息到隊列並從中取出消息。現在是時候介紹RabbitMQ中完整的消息模型了
        //讓我們簡單的概括一下之前的內容:
        //發佈者(producer)是發佈消息的應用程序。
        //隊列(queue)用於消息存儲的緩衝。
        //消費者(consumer)是接收消息的應用程序。

        //MQ消息模型的核心理念是: 發佈者不會直接發送任何消息給隊列 事實上 發佈者甚至不知道消息是否已經被投入到隊列
        // 發佈者只需要把消息發送給一個交換機(Exchanges)
        // 交換機非常簡單  他一邊從發佈者那邊接收消息 一邊把消息推送到隊列
        // 交換機必須知道如何處理他接收到的消息 是應該推送到指定的隊列中還是多個隊列中 或者是直接忽略消息
        // 這些規則是可以通過交換機類型(exchange type)來定義的
        // 交換機類型:
        // 直連交換機 (direct)
        // 主題交換機  (topic)
        // 頭交換機     (headers)
        // 扇交換機     (fanout)
        // 在這個日誌系統中 採用扇交換機類型 從字面意思 應該就能想到 擴散 的一種類型
        // 現在這個場景 我們需要把消息發送給兩個接受者 這種類型剛剛合適
        //綁定交換機
        //創建一個 扇交換機 命名爲 log_queue
       // $this->channel->exchange_declare('log_queue', 'fanout', false, false, false);
        //這裏我們創建一個直連交換機
        $this->channel->exchange_declare('direct_logs', 'direct', false, false, false);
        // 查看所有交換機的列表
        // 命令: rabbitmqctl list_exchanges
        // 這個列表中有一些叫做amq.*的交換器。這些都是默認創建的,不過這時候你還不需要使用他們
        //匿名交換機
        //在調用上面寫的 四個方法的時候 並沒有對交換機進行配置 但仍然可以使用消息發送
        // 因爲我們使用了命名爲空的 字符串默認了交換機     第二個參數就是交換機的名稱
        //$this->channel->basic_publish($msg, '', 'hello');
        // 我們這裏使用的默認或者匿名交換機 消息將會根據指定的routing_key 發到指定的隊列
        // routing key是basic_publish函數的第三個參數 第二個參數爲交換機的名字

        //另外 我們需要把我們的消息也要設置持久化 設置爲 delivery_mode = 2
        $msg=new AMQPMessage($data,array('delivery_mode' => AMQPMessage::DELIVERY_MODE_PERSISTENT) );
        //現在,我們就可以發送消息到一個我們命名的交換機:
        //我們命名了 交換機 第三個參數就不需要再找尋隊列了 只限於扇類型的交換機
     //   $this->channel->basic_publish($msg, 'log_queue');
        //現在我們使用直連交換機 要設置第三個參數
        //我們先假設“severity”的值是info、warning、error中的一個。
        // 這樣我們就可以根據 報錯的等級不同 推送到路由對應不同的隊列進行數據處理了
        // 當然在接收者那邊 也是需要做調整的 這個參數 根據傳進來的值來定
        $severity='';
        $this->channel->basic_publish($msg, 'direct_logs',$severity);
        echo " [x] Sent '",$data,"'\n";
        //臨時隊列
        // 上面的四個方法中 聲明瞭兩個隊列名 ( hello和task_queue)
        //給隊列名稱很重要  我們需要把工作者指定到正確的隊列
        //如果你打算在發佈者(producers)和消費者(consumers)之間共享同隊列的話,給隊列命名是十分重要的



        //這個方法裏的程序 看起來跟上面的四個方法沒什麼區別  唯一的區別就是把消息發送到了交換機上而不是匿名交換機
        //

        //發送完消息後 關閉通道
        $this->channel->close();
        $this->connection->close();
    }

    //需要工作的接受者
    public function log_work(){

        echo ' [*] Waiting for messages. To exit press CTRL+C', "\n";
        // 創建一個交換機
        $this->channel->exchange_declare('log_queue', 'fanout', false, false, false);
        //1.當我們連接上RabbitMQ的時候,我們需要一個全新的、空的隊列。
        //我們可以手動創建一個隨機的隊列名,或者讓服務器爲我們選擇一個隨機的隊列名(推薦)。
        //2.當與消費者(consumer)斷開連接的時候,這個隊列應當被立即刪除

        list($queue_name, ,) = $this->channel->queue_declare("", false, false, true, false);
        //  方法返回時,$queue_name變量包含一個隨機生成的RabbitMQ隊列名稱。例如,類似amq.gen-jzty20brgko-hjmujj0wlg。
        //隊列交換機綁定  只需工作者隊列交換機綁定 發佈任務的人 不需要綁定隊列 只需要把消息推送的交換機中 只限於扇類型交換機
      //  $this->channel->queue_bind($queue_name, 'log_queue');
        //根據傳過來的類型 來確定消息到底推送到哪個隊列中
        // 這裏的 $severities 真正開發中 是接收傳進來的值 我這邊直接寫一個變量
        $severities=[];
        foreach($severities as $severity) {
            $this->channel->queue_bind($queue_name, 'direct_logs', $severity);
        }
        //綁定(binding)是指交換機(exchange)和隊列(queue)的關係。
        //可以簡單理解爲:這個隊列(queue)對這個交換機(exchange)的消息感興趣
        //綁定的時候可以帶上一個額外的參數 routing_key
        //爲了避免與$channel::basic_publish的參數混淆,我們把它叫做綁定鍵(binding key)。以下是如何創建一個帶綁定鍵的綁定
       //做一個解釋
        // 把消息推送到交換機中或者直接推送到隊列中
        // 這個方法是在發送者中使用
        //basic_publish() 方法
        // 三個參數
        //  1.發送的內容 2.交換機的名稱(爲空的話匿名交換機) 3. 路由的名稱(routing_key) 找隊列
        // 如果你起了交換機名稱 第三個參數可省略 發送者只需要把消息發送到交換機中 即可

        // 交換機與隊列的綁定
        //這個方法是在接受者中使用
        //queue_bind() 方法
        //   三個參數
        // 1.隊列名稱 2.交換機名稱  3.路由(routing_key)防止跟上面的方法參數混淆 或者起名叫 綁定鍵(binding_key)

        //$binding_key = 'black';
        //$channel->queue_bind($queue_name, $exchange_name, $binding_key);
        //綁定鍵的意義取決於交換機(exchange)的類型。我們之前使用過的扇型交換機(fanout exchanges)會忽略這個值。

        //現在我們採用直連交換機類型 Direct exchange

        //我們的日誌系統廣播所有的消息給所有的消費者(consumers)。我們打算擴展它,使其基於日誌的嚴重程度進行消息過濾。例如我們也許只是希望將比較嚴重的錯誤(error)日誌寫入磁盤,以免在警告(warning)或者信息(info)日誌上浪費磁盤空間。
        //我們使用的扇型交換機(fanout exchange)沒有足夠的靈活性 —— 它能做的僅僅是廣播

        //我們將會使用直連交換機(direct exchange)來代替。
        //路由的算法很簡單 ——
        // 交換機將會對綁定鍵(binding key)和路由鍵(routing key)進行精確匹配,從而確定消息該分發到哪個隊列
         // 這樣就根據路由名稱來 交換機把消息送到哪個隊列中

        //多個綁定
        //多個隊列使用相同的綁定建是合法的
        //  一個綁定建可以鏈接多個隊列 這樣的話 直連交換機類型 就可以做到 扇形交換機的功能 把消息散播到綁定的隊列中


        //隊列交換機綁定(binding)列表查詢
        // rabbitmqctl list_bindings

        //我們要創建一個回調函數來接收發送者發送的消息
        //消息響應默認是開啓的。之前的例子中我們可以使用no_ack=True標識把它關閉。是時候設置的第四個參數basic_consume爲false
        // (true 意味着不響應ack) ,當工作者(worker)完成了任務,就發送一個響應。
        $this->channel->basic_consume($queue_name, '', false, false, false, false, 'msg');
        //運行上面的代碼,我們發現即使使用CTRL+C殺掉了一個工作者(worker)進程,消息也不會丟失。
        //當工作者(worker)掛掉這後,所有沒有響應的消息都會重新發送。
        //如果在basic_consume 方法第四個參賽爲false 的話 再回調函數裏一定要basic_ack



        // 只要通道註冊了回調,就進行循環
        while ($this->channel ->is_consuming()) {
            $this->channel->wait();
        }

        $this->channel->close();
        $this->connection->close();
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章