RabbitMQ基礎概念和入門使用

什麼是RabbitMQ

RabbitMQ是一個由ErLang語言編寫的實現了AMQP(高級消息隊列協議)的開源消息中間件 。RabbitMQ 支持消息的持久化、事務、擁塞控制、負載均衡等特性。

爲什麼要使用RabbitMQ

在實際開發過程中,我們可能會經常遇到一下情況
1、A系統需要調用B系統,比如發短信,發郵件
2、比如A系統需要同步數據到B系統
按照以往的方式,我們是直接在代碼裏面添加一個調用其它系統的方法。也許我們會使用異步的方式來調用它。但是不管怎樣,這個調用的過程還是發生在我們系統內部,一旦這個過程崩潰,將會導致我們的主業務功能不可用。
因此我們引入了消息中間件,而RabbitMQ就是其中的一種,引入消息中間件爲我們帶來一些幾點好處:

  • 降低耦合度
    把多個系統之間的調用放到了纖細中間件上面,降低了系統的耦合度
  • 異步化
    各個系統之間無需等待即可執行
  • 提高系統吞吐能力
    可以把高峯期的請求裏面耗時到操作緩衝到消息隊列裏面,提高請求的響應速度

AMQP協議

什麼是AMQP協議

AMQP是應用層協議的一個開放標準,爲面向消息的中間件設計。基於此協議的客戶端與消息中間件可傳遞消息,並不受客戶端/中間件不同產品,不同的開
發語言等條件的限制。目標是實現一種在全行業廣泛使用的標準消息中間件技術,以便降低企業和系統集成的開銷,並且向大衆提供工業級的集成服務。

RabbitMQjava客戶端的使用

幾個基本概念

要使用客戶端連接RabbitMQ,那麼首先我們應該弄清楚一下幾個概念:

連接

作爲一個客戶端,如果要和RabbitMQ通信,那麼首先肯定得建立一條TCP連接,同時告訴RabbitMQ,我們是使用AMQP進行交流,那麼這時候就會創建一條AMQP的信道

信道

RabbitMQ使用了多路複用技術來進行通信。在上面的tcp連接創建好之後,RabbitMQ就會創建出信道進行通信,信道是基於在TCP連接上面的虛擬連接,一個TCP連接可以有多個信道,每個信道之間都是私有的,這樣就避免了多次創建TCP連接帶來的性能損耗。

生產者

生產者就是消息的發佈者,把消息發送到RabbitMQ

消費者

消費者通過訂閱指定的隊列來消費生產者發佈的某些消息

交換器,路由鍵,隊列

生產者所生產的消息將會發送到指定的交換器,然後交換器會根據消息的路由鍵進行匹配,發送給綁定了對應的路由鍵的隊列。所以他們之間存在以下的關係:
在這裏插入圖片描述

虛擬主機

虛擬消息服務器,vhost,本質上就是一個 mini 版的 mq 服務器,有自己的隊列、交換器和綁定,最重要的,自己的權限機制。Vhost 提供了邏輯上的
分離,可以將衆多客戶端進行區分,又可以避免隊列和交換器的命名衝突。Vhost 必須在連接時指定,rabbitmq 包含缺省 vhost:“/”,通過缺省用戶和
口令 guest 進行訪問。
rabbitmq 裏創建用戶,必須要被指派給至少一個 vhost,並且只能訪問被指派內的隊列、交換器和綁定。Vhost 必須通過 rabbitmq 的管理控制工具創
建。

交換器類型

  • direct交換器
    路由鍵完全匹配,消息被投遞到對應的隊列, direct 交換器是默認交換器。聲明一個隊列時,會自動綁定到默認交換器,並且以隊列名稱作爲路由鍵
  • Fanout交換器
    消息廣播到綁定的隊列,不管隊列綁定了什麼路由鍵,消息經過交換器,每個隊列都有一份。
  • Topic交換器
    通過使用*和#通配符進行處理,使來自不同源頭的消息到達同一個隊列,. 將路由鍵分爲了幾個標識符,*匹配 一 個,#匹配一個或多個。

簡單的消息生產和消費

生產者代碼(Direct)

 /**
     * @Title:
     * @MethodName:
     * @param
     * @Return
     * @Exception
     * @Description:
     * direct 交換器的路由鍵匹配模式是全匹配,也就是需要完全相等纔可以匹配,所以一般用隊列的名稱作爲路由鍵
     * @author: jenkin
     * @date:  2020-04-11 10:04
     */
    @Test
    public void sendByDirect(){
        Connection connection = Common.getConnection();
        try {
            //創建一個信道,用於消息通信
            Channel channel = connection.createChannel();
            //聲明一個持久化的direct交換器
            channel.exchangeDeclare( DIRECT_EXCHANGE,"direct",true);
            //聲明一個隊列,這裏持久化參數爲true,如果不持久化,那麼一旦mq出故障重啓就會丟失隊列以及隊列裏面的數據
            //這裏exclusive爲false,標識這個隊列可以被多個消費者消費
            //autoDelete爲false,如果爲true的話當隊列裏面沒有消費者之後就會自動刪除,bug前提是要被消費過之後纔會去判斷
            //arguments這是一個map,可以聲明隊列的過期時間,最大空間,長度,以及超時時間
            channel.queueDeclare(DIRECT_QUEUE_1,true,false,false,null);
            //綁定隊列和交換器的關係
            //這裏把DIRECT_QUEUE_1隊列綁定到DIRECT_EXCHANGE 交換器上面,並且使用DIRECT_QUEUE_1作爲路由鍵發送消息
            channel.queueBind(DIRECT_QUEUE_1,DIRECT_EXCHANGE,DIRECT_QUEUE_1);
            //使用信道發送消息
            //mandatory 這個標識如果爲true,那麼如果消息無法被路由的時候就會返調用basic.Return 把消息返回給生產者,
            //可以添加一個ReturnListener ,在消息被返回之後會在這裏進行回調
            // 反之直接丟棄
            channel.basicPublish(DIRECT_EXCHANGE,DIRECT_QUEUE_1,false,null,"測試消息".getBytes());

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

消費者代碼

/**
     * @Title:
     * @MethodName:
     * @param
     * @Return
     * @Exception
     * @Description:
     * 接受direct類型的消息
     * @author: jenkin
     * @date:  2020-04-11 11:05
     */

    public void consumerDirect(){
        Connection connection = Common.getConnection();
        try {
            Channel channel = connection.createChannel();
            channel.basicConsume(DIRECT_QUEUE_1,true,new QueueingConsumer(channel){
                @Override
                public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                    System.out.println("消費者收到消息"+new String(body, StandardCharsets.UTF_8));
                }
            });



        } catch (IOException e) {
            e.printStackTrace();
        }


    }

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章