Spring Boot 整合 RabbitMQ

1. 前言

RabbitMQ是一個消息隊列,消息隊列的功能主要用來

  1. 實現應用服務的異步和解耦,削鋒填谷、消息分發;
  2. 解耦;
  3. 在分佈式系統中,也可用於其他地方,如分佈式事務的支持(阿里的RocketMQ)。

2. RabbitMQ介紹

RabbitMQ是實現AMQP的消息中間件的一種,最初起源於金融系統,用於在分佈式系統中存儲轉發消息,在易用性、擴展性、高可用性等方面表現不俗。RabbitMQ主要是爲了實現系統之間的雙向解耦。當生產者大量生產消息時,消費者無法快速消費,就需要一箇中間層保存這些數據。

AMQP,即 Advanced Message Queuing Protocol,高級消息隊列協議,是應用層協議的一個開放標準,爲面向消息的中間件設計。消息中間件主要用於組件之間的解耦,消息的發送者無需知道消息使用者的存在,反之亦然。AMQP 的主要特徵是面向消息、隊列、路由(包括點對點和發佈/訂閱)、可靠性、安全。

RabbitMQ是一個開源的AMQP實現,服務器端用Erlang語言編寫,支持多種客戶端,如:Python、Ruby、.NET、Java、JMS、C、PHP、ActionScript、XMPP、STOMP 等,支持 AJAX。用於在分佈式系統中存儲轉發消息,在易用性、擴展性、高可用性等方面表現不俗。

3. 概念介紹

生產者、消費者和我們的隊列。在 RabbitMQ 中,中間還增加了一層:交換機(Exchange)。這樣,消息的投遞就不由生產者來決定投遞至哪個隊列,而消息是直接投遞至交換機的,由交換機根據調度策略來決定這個消息需要投遞到哪個隊列。

P:消息的生產者
X:交換機
右側紅色的代表隊列

3.1 交換機(Exchange)

問:爲什麼需要交換機?

答:AMQP協議的核心思想就是生產者和消費者的解耦。生產者講消息發送到一個交換機,先由交換機來接受,再按照交換機特定的策略轉發到Queue進行存儲。

問:交換機收到消息,它是如何確定要把哪些消息發送到哪些Queue?

答:Binding和RoutingKey

Binding表示Exchange和Queue之間的關係,表示隊列與該交換機綁定,綁定可以附帶一個參數RoutingKey。交換機就是根據這個RoutingKey和當前所有綁定的Binding做匹配,如果滿足匹配,就往交換機所綁定的Queue發送消息,這樣我們向RabbitMQ發送一次消息,就可以分發到不同的Queue。Routing的意義依賴於交換機的類型。

下面依次介紹Exchange的三種主要類型:Direct、Topic、Fanout。

3.1.1 Direct Exchange

Direct Exchange是RabbitMQ默認的Exchange,完全根據RoutingKey來路由消息。例如P發送消息的RoutingKey=binding1,則消息進入Queue1。設置Exchange和Queue的Binding時需指定RoutingKey(一般爲Queue的名稱),發消息時也指定一樣的RoutingKey,消息就會被路由到對應的Queue。

3.1.2 Topic Exchange

Topic Exchange 和 Direct Exchange 類似,也需要通過 RoutingKey 來路由消息,區別在於Direct Exchange 對 RoutingKey 是精確匹配,而 Topic Exchange 支持模糊匹配。分別支持 * 和 # 通配符,* 表示匹配一個單詞, # 則表示匹配沒有或者多個單詞。

3.1.3 Headers Exchange

Headers類型的Exchange不依賴於routing key與binding key的匹配規則來路由消息,而是根據發送的消息內容中的headers屬性進行匹配。 在綁定Queue與Exchange時指定一組鍵值對;當消息發送到Exchange時,RabbitMQ會取到該消息的headers(也是一個鍵值對的形式),對比其中的鍵值對是否完全匹配Queue與Exchange綁定時指定的鍵值對;如果完全匹配則消息會路由到該Queue,否則不會路由到該Queue。

3.1.4 Default Exchange

Default Exchange 是一種特殊的 Direct Exchange。當你手動創建一個隊列時,後臺會自動將這個隊列綁定到一個名稱爲空的 Direct Exchange 上,綁定 RoutingKey 與隊列名稱相同。有了這個默認的交換機和綁定,使我們只關心隊列這一層即可,這個比較適合做一些簡單的應用。

3.1.5 RPC

MQ本身是基於異步的消息處理,前面的示例中所有的生產者(P)將消息發送到RabbitMQ後不會知道消費者(C)處理成功或者失敗(甚至連有沒有消費者來處理這條消息都不知道)。 但實際的應用場景中,我們很可能需要一些同步處理,需要同步等待服務端將我的消息處理完成後再進行下一步處理。這相當於RPC(Remote Procedure Call,遠程過程調用)。在RabbitMQ中也支持RPC。

RabbitMQ中實現RPC的機制是:

  • 客戶端發送請求(消息)時,在消息的屬性(MessageProperties ,在AMQP 協議中定義了14中properties ,這些屬性會隨着消息一起發送)中設置兩個值replyTo (一個Queue 名稱,用於告訴服務器處理完成後將通知我的消息發送到這個Queue 中)和correlationId (此次請求的標識號,服務器處理完成後需要將此屬性返還,客戶端將根據這個id瞭解哪條請求被成功執行了或執行失敗)
  • 服務器端收到消息並處理
  • 服務器端處理完消息後,將生成一條應答消息到replyTo 指定的Queue ,同時帶上correlationId 屬性
  • 客戶端之前已訂閱replyTo 指定的Queue ,從中收到服務器的應答消息後,根據其中的correlationId屬性分析哪條請求被執行了,根據執行結果進行後續業務處理。

4. Spring Boot 整合 RabbitMQ

Spring Boot 整合 RabbitMQ 非常簡單,如果只是簡單的使用配置非常少,Spring Boot 提供了 spring-boot-starter-amqp 項目對消息各種支持。

  1. 引入依賴
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-amqp</artifactId>
    </dependency>

     

  2. 配置RabbitMQ
    # rabbitmq配置
    spring.rabbitmq.host=localhost
    spring.rabbitmq.port=5672
    spring.rabbitmq.username=admin
    spring.rabbitmq.password=123456
    spring.rabbitmq.virtual-host=scheduled_vhost
    spring.rabbitmq.publisher-confirms=true
    spring.rabbitmq.publisher-returns=true
    spring.rabbitmq.listener.direct.acknowledge-mode=manual
    spring.rabbitmq.listener.simple.acknowledge-mode=manual
    spring.rabbitmq.listener.simple.concurrency=10
    spring.rabbitmq.listener.simple.max-concurrency=50
    #隊列名稱
    spring.rabbitmq.template.queue=ctv_els_refresh_data

     

  3. 簡單使用
@Slf4j
@Component
public class MqConfiguration {

    @Autowired
    private AmqpTemplate rabbitTemplate;

    public void sendMessage(String name, String creditCode, String regNo) {
        Map map = new HashMap<>();
        map.put("name", name);
        map.put("credit_no", creditCode);
        map.put("reg_no", regNo);
        rabbitTemplate.convertAndSend("ctv_els_refresh","", map);
        log.info(">>> 隊列發送成功:{}-{}",creditCode , name);
    }

}

 

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