RabbitMq底層原理分析

南方菇涼發表於2019-04-22

RabbitMq訊息中介軟體介紹&為什麼要使用訊息中介軟體&什麼時候使用訊息中介軟體

我們用java來舉例子, 打個比方我們客戶端傳送一個下單請求給訂單系統(order)訂單系統傳送了 一個請求給我們的庫存系統告訴他需要更改庫存了,我已經下單了,這裡,每一個請求我們都可以看作一條訊息,但是我們客戶端需要等待訂單系統告訴我這條訊息的處理結果(我到底有沒有下單成功) 但是 訂單系統不需要知道庫存系統這條訊息的處理情況 因為無論你庫存有沒有改動成功, 我訂單還是下了, 因為是先下完了訂單(下成功了) 才去更改庫存, 庫存如果更改出BUG了 那是庫存系統的問題, 這個BUG不會影響訂單系統。 如果這裡你能理解的話,那麼我們就能發現我們使用者傳送的這條訊息(下訂單),是需要同步的(我需要知道結果),訂單傳送給庫存的訊息,是可以非同步的(我不想知道你庫存到底改了沒,我只是通知你我這邊成功下了一個訂單)那麼如果我們還按原來的方式去實現這個需求的話, 那麼結果會是這樣:

RabbitMq底層原理分析

那可能有同學說了, 我們訂單系統開闢執行緒去訪問庫存系統不就好了嗎?

RabbitMq底層原理分析

使用執行緒池解決 確實可以, 但是也有他的缺點, 那麼 到底怎麼來完美解決這個問題呢?

RabbitMq底層原理分析

如果這張圖能理解的話, 那麼 這個訊息系統, 就是我們的訊息中介軟體。

RabbitMq介紹&AMQP介紹

導語:我們剛剛介紹了什麼是訊息中介軟體, 那麼RabbitMq就是對於訊息中介軟體的一種實現,市面上還有很多很多實現, 比如RabbitMq、ActiveMq、ZeroMq、kafka,以及阿里開源的RocketMQ等等 我們這節主要講RabbitMq

AMQP

RabbitMq底層原理分析

這裡引用百度的一句話 再加以我的理解: AMQP 其實和Http一樣 都是一種協議, 只不過 Http是針對網路傳輸的, 而AMQP是基於訊息佇列的 AMQP 協議中的基本概念: •Broker: 接收和分發訊息的應用,我們在介紹訊息中介軟體的時候所說的訊息系統就是Message Broker。 •Virtual host: 出於多租戶和安全因素設計的,把AMQP的基本元件劃分到一個虛擬的分組中,類似於網路中的namespace概念。當多個不同的使用者使用同一個RabbitMQ server提供的服務時,可以劃分出多個vhost,每個使用者在自己的vhost建立exchange/queue等。 •Connection: publisher/consumer和broker之間的TCP連線。斷開連線的操作只會在client端進行,Broker不會斷開連線,除非出現網路故障或broker服務出現問題。 •Channel: 如果每一次訪問RabbitMQ都建立一個Connection,在訊息量大的時候建立TCP Connection的開銷將是巨大的,效率也較低。Channel是在connection內部建立的邏輯連線,如果應用程式支援多執行緒,通常每個thread建立單獨的channel進行通訊,AMQP method包含了channel id幫助客戶端和message broker識別channel,所以channel之間是完全隔離的。Channel作為輕量級的Connection極大減少了作業系統建立TCP connection的開銷。 •Exchange: message到達broker的第一站,根據分發規則,匹配查詢表中的routing key,分發訊息到queue中去。常用的型別有:direct (point-to-point), topic (publish-subscribe) and fanout (multicast)。 •Queue: 訊息最終被送到這裡等待consumer取走。一個message可以被同時拷貝到多個queue中。 •Binding: exchange和queue之間的虛擬連線,binding中可以包含routing key。Binding資訊被儲存到exchange中的查詢表中,用於message的分發依據。 Exchange的型別: direct : 這種型別的交換機的路由規則是根據一個routingKey的標識,交換機通過一個routingKey與佇列繫結 ,在生產者生產訊息的時候 指定一個routingKey 當繫結的佇列的routingKey 與生產者傳送的一樣 那麼交換機會吧這個訊息傳送給對應的佇列。 fanout: 這種型別的交換機路由規則很簡單,只要與他繫結了的佇列, 他就會吧訊息傳送給對應佇列(與routingKey沒關係) topic:(因為*在這個筆記軟體裡面是關鍵字,所以下面就用星替換掉了) 這種型別的交換機路由規則也是和routingKey有關 只不過 topic他可以根據:星,#( 星號代表過濾一單詞,#代表過濾後面所有單詞, 用.隔開)來識別routingKey 我打個比方 假設 我繫結的routingKey 有佇列A和B A的routingKey是:星.user B的routingKey是: #.user 那麼我生產一條訊息routingKey 為: error.user 那麼此時 2個佇列都能接受到, 如果改為 topic.error.user 那麼這時候 只有B能接受到了 headers: 這個型別的交換機很少用到,他的路由規則 與routingKey無關 而是通過判斷header引數來識別的, 基本上沒有應用場景,因為上面的三種型別已經能應付了。

RabbitMQ MQ: message Queue 顧名思義 訊息佇列, 佇列大家都知道, 存放內容的一個東西, 存放的內容先進先出, 訊息佇列, 只是裡面存放的內容是訊息而已。 RabbitMq 是一個開源的 基於AMQP協議實現的一個完整的企業級訊息中介軟體,服務端語言由Erlang(面向併發程式設計)語言編寫 對於高併發的處理有著天然的優勢,客戶端支援非常多的語言: •Python •Java •Ruby •PHP •C# •JavaScript •Go •Elixir •Objective-C •Swift

RabbitMQ服務端部署

在介紹訊息中介軟體的時候所提到的“訊息系統” 便是我們這節的主題:RabbitMq 如同redis一樣 他也是採用c/s架構 由服務端 與客戶端組成, 我們現在我們計算機上部署他的服務端 由於我們剛剛介紹過了RabbitMQ服務端是由Erlang語言編寫所以我們這裡先下載Erlang語言的環境 注意:如果是在官網下的RabbitMQ服務端的話 Erlang語言的版本不能太低, 不然要解除安裝掉舊的去裝新的, 我們這裡下載OTP21.0版本直接從外網下載會很慢, 我這裡直接貼上百度網盤的地址(因為這個東西還是有點大的) pan.baidu.com/s/1pZJ8l2f3… 我們再去官網下載 他的服務端安裝包 www.rabbitmq.com/download.ht… 根據自己的系統選擇下載即可 注意! 需要先下載Erlang再下載安裝包安裝, 不然安裝RabbitMQ服務端的時候會提示你本地沒有Erlang環境

安裝的話, 基本上就是預設的選項不用改 如何看RabbitMq安裝完成了? 在系統-服務中找到如下即可:

RabbitMq底層原理分析

包括啟動 停止 重啟 服務等

RabbitMQ安裝會附帶一個管理工具(方便我們能直觀的檢視整個RabbitMQ的執行狀態和詳細資料等,有點像Navicat 對應Mysql的關係) 值得一提的是, 管理工具和RabbitMQ是兩碼事 希望同學們不要混稀了。 管理工具啟動方式: 到你們安裝的 RabbitMQ Server\rabbitmq_server-3.7.12\sbin 目錄下面 執行一條cmd命令: rabbitmq-plugins enable rabbitmq_management 直接複製這條命令即可 , 當然 嫌每次都要去目錄中去執行的麻煩的話, 可以配置一個環境變數 或者在我們的開始選單欄中找到這個:

RabbitMq底層原理分析

輸入完啟動命令後 稍微等一下會有結果返回 然後可以開啟瀏覽器 輸入 http://127.0.0.1:15672 訪問管理頁面:

RabbitMq底層原理分析

預設賬號密碼都是 guest 即 username :guest password:guest 登入進去之後會看到如下介面(因為我不小心裝了2次RabbitMq 所以這裡能看到都重複了, 你們自己那不會重複,然後我們剛剛說了 管理工具和rabbitmq 是兩碼事 所以埠也就不一樣)

RabbitMq底層原理分析

這個頁面在筆記裡面介紹起來可能比較複雜, 就不一一介紹了, 我這裡講個重點, 就是線上環境下一定要吧guest使用者(當然 guest這個使用者只能本機才能登陸)刪掉並且新加一個使用者, 這裡就演示一下這個功能 首先 點選admin頁籤, 在下面找到Add User

RabbitMq底層原理分析

然後輸入賬號 密碼 確認密碼 這個Tags其實是一個使用者許可權標籤, 關於他的介紹可以看官方介紹(點旁邊那個小問號就好了,我這裡直接翻譯他的介紹)

RabbitMq底層原理分析

RabbitMq底層原理分析

RabbitMq底層原理分析

填寫完之後點選AddUser 就可以新增一個使用者了, 新增完使用者之後還要給這個使用者新增對應的許可權(注:Targ不等於許可權) 比如說 我剛剛新增了一個jojo角色

RabbitMq底層原理分析

點選這個jojo可以進去給他新增許可權 這個許可權可以是 Virtual host 級別的 也可以是交換機級別的 甚至是細化到某一個讀寫操作 我這裡就給他新增一個Virtual host許可權

RabbitMq底層原理分析

這裡 我們給了他 testhost這個Virtual host的許可權 正則匹配都是* 也就是所有許可權 然後點選set新增完畢 那麼管理頁面 我們就講到這裡

RabbitMq快速開始

因為我們這裡是用java來作為客戶端, 我們首先引入maven依賴: <dependency> <groupId>com.rabbitmq</groupId> <artifactId>amqp-client</artifactId> <version>5.1.2</version> </dependency> (注意的是, 我這裡引入的是5.x的rabbitmq客戶端版本, 那麼我們jdk的版本最好在8以上,反之, 這裡就建議使用4.x的版本,這裡僅僅討論jdk8 其他的版本不做討論) 首先 我們編寫一個連線的工具類: `package com.luban.util;

import com.rabbitmq.client.Connection; import com.rabbitmq.client.ConnectionFactory;

import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map;

/**

  • 需要諮詢java高階VIP課程的同學可以木蘭老師的QQ:2746251334

  • 需要往期視訊的同學可以加加安其拉老師的QQ:3164703201

  • author:魯班學院-商鞅老師 */ public class ConnectionUtil {

    public static final String QUEUE_NAME = "testQueue";

    public static final String EXCHANGE_NAME = "exchange";

    public static Connection getConnection() throws Exception{ //建立一個連線工廠 ConnectionFactory connectionFactory = new ConnectionFactory(); //設定rabbitmq 服務端所在地址 我這裡在本地就是本地 connectionFactory.setHost("127.0.0.1"); //設定埠號,連線使用者名稱,虛擬地址等 connectionFactory.setPort(5672); connectionFactory.setUsername("jojo"); connectionFactory.setPassword("jojo"); connectionFactory.setVirtualHost("testhost"); return connectionFactory.newConnection(); }

}`

然後我們編寫一個消費者(producer),和一個生產者(consumer): 生產者: `public class Consumer {

public static void sendByExchange(String message) throws Exception {

    Connection connection = ConnectionUtil.getConnection();
    Channel channel = connection.createChannel();
    //宣告佇列
    channel.queueDeclare(ConnectionUtil.QUEUE_NAME,true,false,false,null);
    // 宣告exchange
    channel.exchangeDeclare(ConnectionUtil.EXCHANGE_NAME, "fanout");
    //交換機和佇列繫結
    channel.queueBind(ConnectionUtil.QUEUE_NAME, ConnectionUtil.EXCHANGE_NAME, "");
    channel.basicPublish(ConnectionUtil.EXCHANGE_NAME, "", null, message.getBytes());
    System.out.println("傳送的資訊為:" + message);
    channel.close();
    connection.close();
}
複製程式碼

} `

消費者: `public class Producer {

public static void getMessage() throws Exception {
    Connection connection = ConnectionUtil.getConnection();
    Channel channel = connection.createChannel();
複製程式碼

// channel.queueDeclare(ConnectionUtil.QUEUE_NAME,true,false,false,null); DefaultConsumer deliverCallback = new DefaultConsumer(channel) { @Override public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { System.out.println(new String(body, "UTF-8")); } }; channel.basicConsume(ConnectionUtil.QUEUE_NAME, deliverCallback); }

} `

這裡, 我們演示繫結fanout的型別的交換機, 所以不需要routingKey 就可以路由只需要繫結即可 (可能有同學要問了, 如果沒有繫結交換機怎麼辦呢? 沒有繫結交換機的話, 訊息會發給rabbitmq預設的交換機裡面 預設的交換機隱式的繫結了所有的佇列,預設的交換機型別是direct 路由建就是佇列的名字) 基本上這樣子的話就已經進行一個快速入門了, 由於我們現在做專案基本上都是用spring boot(就算沒用spring boot也用spring 吧) 所以後面我們直接基於spring boot來講解(rabbitmq的特性,實戰等)

相關文章