RabbitMQ各功能入門

smartdt發表於2018-05-31

一、RabbitMQ相關角色

RabbitMQ整體上是一個生產者與消費者模型,主要負責接收、儲存和轉發訊息,可以把訊息傳遞的過程想象成:你將一個包裹收到郵局,郵局會暫存並最終將包裹由快遞員送到收件人的手上。RabbitMQ就好比由郵局、郵箱和郵遞員組成的一個系統,從計算機術語來說,RabbitMQ模型更像是一種交換機模型。如下圖(RabbitMQ的模型框架):


二、生產者和消費者

Ⅰ:Producer:生產者,就是投遞訊息的一方。

生產者建立訊息,然後釋出到RabbitMQ中,訊息一般可以包含2個部分:訊息體和標籤(label)。也可成為payload,在應用中,訊息體一般是一個帶有業務邏輯結構的資料,如JSON串。生產者把訊息交給RabbitMQ,RabbitMQ之後會根據標籤把訊息傳送給感興趣的消費者(Consumer)。

Ⅱ:Consumer:消費者,就是接收訊息的一方。

消費者連線到RabbitMQ伺服器,並訂閱到佇列上。當消費者消費一條訊息時,只是消費訊息的訊息體(payload),在訊息路由的過程中,訊息的標籤會丟棄,存入到佇列中的訊息只有訊息體,消費者也只會消費到訊息體,也就不知道訊息的生產者是誰,也不需要知道。

Ⅲ:Broker:訊息中介軟體的服務節點。

對於RabbitMQ來說,一個RabbitMQ Broker可以簡單的看作一個RabbitMQ服務節點,或者RabbitMQ服務例項。大多數情況下可以將RabbitMQ Broker看作一臺RabbitMQ伺服器。

Ⅳ:整個流程,如圖:

生產者將訊息存入RabbitMQ Broker中,消費者從Broker中消費資料的整個過程:

首先生產者將業務方資料進行可能的包裝,然後封裝成訊息,傳送到Broker中,消費者訂閱並接收訊息,經過可能的解包處理得到原始資料,在進行業務邏輯處理。這個業務邏輯處理並不一定需要和接收訊息的邏輯使用同一個執行緒,消費者可以使用一個執行緒去接收訊息,存到記憶體中,比如使用java的BlockingQueue。業務處理邏輯使用另一個執行緒從記憶體中讀取資料,這樣可以將應用進一步解耦,提供整個應用的處理效率。


三、佇列

Ⅰ:Queue:佇列,是RabbitMQ的內部物件,用於儲存訊息。

RabbitMQ中訊息都只能儲存在佇列中,這一點和Kafka這種訊息中介軟體相反。Kafka將訊息儲存在topic這個邏輯層。RabbitMQ的生產者生產訊息並最終投遞到佇列中,消費者可以從佇列中獲取訊息並消費。多個消費者可以訂閱同一個佇列,這時佇列中的訊息會被平均分攤(Round-Robin,輪詢)給多個消費者進行處理,而不是每個消費者都收到所有的訊息並處理。


四、交換器、路由鍵、繫結

Ⅰ:Exchange:交換器。

生產者將訊息傳送到Exchange(交換器,通常用大寫的“X”表示),由交換器將訊息路由到一個或者多個佇列中,如果路由不到,或許會返回給生產者,或許直接丟棄,這裡可以將RabbitMQ中的交換器看作一個簡單的實體。


RoutingKey:路由鍵。生產者將訊息發給交換器的時候,一般會指定一個RoutingKey,用來指定這個訊息的路由規則,而這個RoutingKey需要與交換器型別和繫結鍵(BindingKey)聯合使用才能最終生效。在交換器型別和繫結鍵固定的情況下,生產者可以在傳送訊息給交換器時,通過指定的RoutingKey來決定訊息流向哪裡。

Binding:繫結。RabbitMQ中通過繫結將交換器與佇列關聯起來,在繫結的時候一般會指定一個繫結鍵(BindingKey),這樣RabbitMQ知道如果正確的將訊息路由到佇列了。


生產者將訊息傳送給交換器時,需要一個RoutingKey,當BindingKey和RoutingKey相匹配時,訊息會被路由到對應的佇列中。在繫結多個佇列到同一個交換器的時候,這些繫結允許使用相同的BindingKey。BindingKey並不是在所有的情況下都生效,它依賴於交換器型別,比如fanout型別的交換器就會無視BindingKey,而是將訊息路由到所有繫結到該交換器的佇列中。

示例程式碼:

public class RabbitProducer {

    private static final String DEMO_NAME = "exchange_demo";
    private static final String ROUTING_KEY = "routingkey_demo";
    private static final String QUEUE_NAME = "queue_name";
    private static final String IP_ADDRESS = "127.0.0.1";
    private static final int PORT = 5672;
    private static final String USERNAME = "root";
    private static final String PASSWORD = "root123";

    public static void main(String[] args) throws IOException, TimeoutException {
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost(IP_ADDRESS);
        factory.setPort(PORT);
        factory.setUsername(USERNAME);
        factory.setPassword(PASSWORD);
        Connection connection = factory.newConnection(); //建立連線
        Channel channel = connection.createChannel(); //建立通道
        //建立一個type="direct"、持久化、非自動刪除的交換器
        channel.exchangeDeclare(DEMO_NAME, "direct", true, false, null);
        //建立一個持久化、非排他的、非自動刪除的佇列
        channel.queueDeclare(QUEUE_NAME, true, false, false, null);
        //將交換器與佇列通過路由鍵繫結
        channel.queueBind(QUEUE_NAME, DEMO_NAME, ROUTING_KEY);
        String message = "Hello RabbitMQ~"; //傳送一條持久化的訊息
        channel.basicPublish(DEMO_NAME, ROUTING_KEY, MessageProperties.PERSISTENT_TEXT_PLAIN, message.getBytes());
        channel.close();
        connection.close();//關閉資源
    }
}

以上程式碼宣告瞭一個direct型別的交換器,然後將交換器和佇列繫結起來。注意這裡使用的字樣是“ROUTING_KEY”,在本該使用BindingKey的channel.queueBind方法中卻和channel.basicPublish方法同樣使用了RoutingKey,這樣做的潛臺詞是:這裡的RoutingKey和BindingKey是同一個東西。在direct交換器型別下,RoutingKey和BindingKey需要完全匹配才能使用,所以上面程式碼中採用了此種寫法會顯得方便許多。

交換器相當於投遞包裹的郵箱,RoutingKey相當於填寫在包裹上的地址,BindingKey相當於包裹的目的地,當填寫在包裹上的地址和實際想要投遞的地址相匹配時,那麼這個包裹就會被正確投遞到目的地,最後這個目的地的“主人”——佇列可以保留這個包裹。如果填寫的地址出錯,郵遞員不能正確投遞到目的地,包裹可能會回退給寄件人,也有可能被丟棄。

五、交換器型別

RabbitMQ常用的交換器型別有fanout、direct、topic、headers四種。

  1. fanout:它會把所有傳送到該交換器的訊息路由到所有與該交換器繫結的佇列中。
  2. direct:它會把訊息路由到那些BindingKey和RoutingKey完全匹配的佇列中。如下圖:warning、info、debug。
  3. topic:它與direct型別相似,但匹配規則不同。(a:RoutingKey為一個點“.”分隔的字串,BindingKey也一樣是“.”分隔;b:BindingKey中可以存在2種特殊字串“*”和“#”,用於做模糊匹配,其中“*”匹配一個單詞,“#”用於匹配多個單詞)
  4. headers:不依賴於路由鍵的匹配規則來路由訊息,而是根據傳送的訊息中的headers屬性進行匹配。

六、RabbitMQ運轉流程

1.生產者傳送訊息的過程

  • 1.生產者連線到RabbitMQ Broker,建立一個連線(connection),開啟一個通道(channel);
  • 2.生產者宣告一個交換器,並設定相關屬性,如:交換機型別、是否持久化等;
  • 3.生產者宣告一個佇列並設定相關屬性,比如是否排他,是否持久化、是否自動刪除等;
  • 4.生產者通過路由鍵將交換器和佇列繫結起來;
  • 5.生產者傳送訊息到RabbitMQ Broker,其中包含路由鍵、交換器等資訊;
  • 6.相應的交換器根據接收到的路由鍵查詢相匹配的佇列;
  • 7.如果找到,則將從生產者傳送過來的訊息存入到響應的佇列中;
  • 8.如果沒有找到,則根據生產者配置屬性選擇是丟棄還是回退給生產者;
  • 9.關閉通道;
  • 10.關閉連線。

2.消費者接收訊息的過程

  • 1.消費者連線到RabbitMQ Broker,建立一個連線(connection),開啟一個通道(channel);
  • 2.消費者想RabbitMQ Broker請求消費相應的佇列的訊息,可能會設定相應的回撥函式和一些準備工作;
  • 3.等待RabbitMQ Broker回應並投遞相應佇列的訊息,消費者接收訊息;
  • 4.消費者確認(ack)接收到的訊息;
  • 5.RabbitMQ從佇列中刪除相應已經被確認的訊息;
  • 6.關閉通道;
  • 7.關閉連線。




新手一枚,歡迎指正拍磚~ ~ ~

相關文章