RabbitMQ 入門(二)基本結構和訊息模型

努力--坚持發表於2024-10-13

一、RabbitMQ的基本結構、角色和訊息模型
MQ的基本結構:

RabbitMQ中的一些角色:

- publisher:生產者
- consumer:消費者
- exchange個:交換機,負責訊息路由
- queue:佇列,儲存訊息
- virtualHost:虛擬主機,隔離不同租戶的exchange、queue、訊息的隔離

RabbitMQ官方提供了5個不同的Demo示例,對應了不同的訊息模型:

1.Basic Queue(基本訊息佇列) 簡單佇列模型 ‌簡單模式‌:在這種模式下,生產者將訊息傳送到佇列,消費者監聽佇列並消費訊息。訊息被消費後,會自動從佇列中刪除。這種模式的優點是簡單易懂,但缺點是如果消費者處理訊息的速度慢,可能會導致訊息處理不及時。

2.Work queues(工作訊息佇列) ,也被稱為(Task queues),任務模型。簡單來說就是讓多個消費者繫結到一個佇列,共同消費佇列中的訊息。 工作佇列模型 ,一個生產者將訊息分發給多個消費者。當訊息處理比較耗時的時候,可能生產訊息的速度會遠遠大於訊息的消費速度。長此以往,訊息就會堆積越來越多,無法及時處理。此時就可以使用work 模型,多個消費者共同處理訊息處理,速度就能大大提高了。‌工作模式‌:在這種模式下,多個消費者競爭同一個佇列中的訊息,誰先獲取到訊息誰就處理該訊息。這種模式適用於處理高併發的情況,但需要注意避免多個消費者處理同一訊息的問題。

釋出訂閱(Publish、 Subscribe) ,又根據交換機型別不同分為三種:

Exchange(交換機)只負責轉發訊息,不具備儲存訊息的能力,因此如果沒有任何佇列與Exchange繫結,或者沒有符合路由規則的佇列,那麼訊息會丟失!

3.Fanout Exchange(廣播)
釋出/訂閱模型 ,生產者釋出訊息,多個消費者同時收取


4.Topic Exchange(主題 )Topic型別的Exchange與Direct相比,都是可以根據RoutingKey把訊息路由到不同的佇列。只不過Topic型別Exchange可以讓佇列在繫結Routing key`的時候使用萬用字元!主題模式‌:主題模式是路由模式的一種變體,它使用萬用字元來匹配路由鍵,使得訊息可以傳送到多個佇列中。這種模式增加了訊息的靈活性,但也需要小心設計萬用字元規則以避免不必要的訊息匹配。

5.Direct Exchange(路由 )

‌路由模式‌:在這種模式下,生產者將訊息傳送到交換機,交換機根據路由鍵將訊息路由到特定的佇列中,只有繫結了相應路由鍵的佇列才能接收訊息。這種模式適用於需要根據不同業務場景處理不同訊息的情況。

二、入門案例 (基本訊息佇列)
簡單佇列模式的模型圖:

官方的HelloWorld是基於最基礎的訊息佇列模型來實現的,只包括三個角色:

- publisher:訊息釋出者,將訊息傳送到佇列queue
- queue:訊息佇列,負責接受並快取訊息
- consumer:訂閱佇列,處理佇列中的訊息

工程包括三部分:

- mq-demo:父工程,管理專案依賴
- publisher:訊息的傳送者
- consumer:訊息的消費者

基本訊息佇列的訊息傳送流程:

1. 建立connection

2. 建立channel

3. 利用channel宣告佇列

4. 利用channel向佇列傳送訊息

publisher程式碼如下:

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import org.junit.Test;
 
import java.io.IOException;
import java.util.concurrent.TimeoutException;
 
public class PublisherTest {
    @Test
    public void testSendMessage() throws IOException, TimeoutException {
        // 1.建立連線
        ConnectionFactory factory = new ConnectionFactory();
        // 1.1.設定連線引數,分別是:主機名、埠號、vhost、使用者名稱、密碼
        factory.setHost("192.168.150.101");
        factory.setPort(5672);
        factory.setVirtualHost("/");
        factory.setUsername("rbmq");
        factory.setPassword("123456");
        // 1.2.建立連線
        Connection connection = factory.newConnection();
 
        // 2.建立通道Channel
        Channel channel = connection.createChannel();
 
        // 3.建立佇列
        String queueName = "simple.queue";
        channel.queueDeclare(queueName, false, false, false, null);
 
        // 4.傳送訊息
        String message = "hello, rabbitmq!";
        channel.basicPublish("", queueName, null, message.getBytes());
        System.out.println("傳送訊息成功:【" + message + "】");
 
        // 5.關閉通道和連線
        channel.close();
        connection.close();
 
    }
}

基本訊息佇列的訊息接收流程:

1. 建立connection

2. 建立channel

3. 利用channel宣告佇列

4. 定義consumer的消費行為handleDelivery()

5. 利用channel將消費者與佇列繫結

consumer程式碼如下:

import com.rabbitmq.client.*;
 
import java.io.IOException;
import java.util.concurrent.TimeoutException;
 
public class ConsumerTest {
 
    public static void main(String[] args) throws IOException, TimeoutException {
        // 1.建立連線
        ConnectionFactory factory = new ConnectionFactory();
        // 1.1.設定連線引數,分別是:主機名、埠號、vhost、使用者名稱、密碼
        factory.setHost("192.168.150.101");
        factory.setPort(5672);
        factory.setVirtualHost("/");
        factory.setUsername("rbmq");
        factory.setPassword("123456");
        // 1.2.建立連線
        Connection connection = factory.newConnection();
 
        // 2.建立通道Channel
        Channel channel = connection.createChannel();
 
        // 3.建立佇列
        String queueName = "simple.queue";
        channel.queueDeclare(queueName, false, false, false, null);
 
        // 4.訂閱訊息
        channel.basicConsume(queueName, true, new DefaultConsumer(channel){
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope,
                                       AMQP.BasicProperties properties, byte[] body) throws IOException {
                // 5.處理訊息
                String message = new String(body);
                System.out.println("接收到訊息:【" + message + "】");
            }
        });
        System.out.println("等待接收訊息。。。。");
    }
}

演示測試成功。

相關文章