Bootstrap

RabbitMQ

​​​​​​ 本文参考:RabbitMQ官方文档

1. 简介

        RabbitMQ是一个开源的消息代理和队列服务器,它提供了一个可靠的消息传递服务,适用于多种场景,包括但不限于异步处理、应用解耦、流量控制和提高消息系统的可靠性。RabbitMQ遵循AMQP(Advanced Message Queuing Protocol)协议,同时也支持其他消息协议,如STOMP、MQTT等。

关键特性以及概念:

  1. 消息(Message)

    消息是传递数据的基本单位,包含有效载荷(payload)和一些属性(如路由键、优先级等)。
  2. 队列(Queue)

    队列是消息的容器,它们存储等待处理的消息。队列是消息的缓冲区,可以存储消息,直到有消费者准备好处理它们。
  3. 交换器(Exchange)

    交换器是RabbitMQ中的核心组件,负责接收来自生产者的消息,并将它们路由到一个或多个队列。交换器有不同类型,包括direct、topic、fanout和headers等,每种类型根据特定的规则来路由消息。
  4. 绑定(Binding)

    绑定是交换器、队列和路由键之间的关系定义。通过绑定,你可以定义消息如何从交换器路由到队列。
  5. 路由键(Routing Key)

    路由键是一个字符串,用于确定消息如何通过交换器路由到队列。它的使用方式取决于交换器的类型。
  6. 虚拟主机(Virtual Host)

    虚拟主机是RabbitMQ服务器的逻辑分区,它们提供了隔离的环境,允许不同的应用程序或不同的部分应用程序使用不同的交换器、队列和绑定,而不会相互干扰。
  7. 持久化(Persistence)

    RabbitMQ支持消息和队列的持久化,这意味着即使在服务器重启之后,消息也不会丢失。
  8. 集群(Clustering)

    RabbitMQ支持集群部署,可以横向扩展以提供更高的吞吐量和可用性。
  9. 高可用性(High Availability)

    通过镜像队列和故障转移机制,RabbitMQ可以在部分节点失败的情况下继续处理消息。
  10. 消息确认(Message Acknowledgments)

    消费者可以发送确认信号,告知消息已经成功处理。这有助于确保消息不会被意外丢失。
  11. 死信队列(Dead Letter Exchanges)

    当消息无法被正常处理时,可以被发送到死信队列,以便后续分析和处理。
  12. 延迟消息(Delayed Messages)

    RabbitMQ支持延迟消息,允许消息在一段时间后再被消费。

2. 基本消息传输流程

交换器、队列和路由键之间的工作流程:

  1. 生产者(Producer) 发送消息到 交换器(Exchange),并指定一个 路由键(Routing Key)

  2. 交换器(Exchange) 根据其类型和路由键来决定如何处理消息:

    1. Direct Exchange:查找具有完全相同路由键的绑定。

    2. Topic Exchange:查找匹配模式的绑定。

    3. Fanout Exchange:不使用路由键,将消息发送到所有绑定的队列。

    4. Headers Exchange:查找具有匹配header属性的绑定。

  3. 交换器(Exchange) 根据上述规则将消息路由到一个或多个 队列(Queue)

如果没有绑定关系,那么:

  • Direct ExchangeTopic Exchange 会丢弃消息,因为没有绑定的队列可以接收它。

  • Fanout Exchange 会将消息发送到所有绑定的队列,不论路由键是什么,因为扇形交换器不使用路由键进行路由。

  • Headers Exchange 也会丢弃消息,因为没有绑定的队列可以匹配消息的header属性。

3. 相关概念图

  • 工作队列

工作队列(又称任务队列)背后的主要思想是避免立即执行资源密集型任务并等待其完成。相反,将任务安排在稍后完成。将任务封装 消息并将其发送到队列。在后台运行的工作进程将弹出任务并最终执行该作业。当运行许多工作进程时,任务将在它们之间共享。

 

  • 路由

根据不同的routingKey将消息推送到不同的queue。

  • 发布订阅

使用相同的绑定键绑定多个队列是完全合法的。在X和之间添加绑定,Q1绑定键为vlog。在这种情况下,交换机direct将表现得像fanout并将消息广播到所有匹配的队列。具有路由键的消息vlog将同时传递给 Q1Q2。

4. 案例

定义交换器、路由键、队列之间的关系

import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class RabbitConfig {

    // 定义队列
    @Bean
    public Queue myQueue() {
        return new Queue("queue", true); // true表示队列持久化
    }

    // 定义Direct交换器
    @Bean
    public DirectExchange myExchange() {
        return new DirectExchange(" exchange");
    }

    // 定义队列和交换器之间的绑定
    @Bean
    public Binding binding(Queue myQueue, DirectExchange myExchange) {
        return BindingBuilder.bind(myQueue).to(myExchange).with("routingKey");
    }
}

发送消息

package com.xiaokai.service;

import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * Author:yang
 * Date:2024-10-15 15:02
 */
@Service
public class SendService {


    @Autowired
    private RabbitTemplate rabbitTemplate;

    public void sendMessage(String message){
        rabbitTemplate.convertAndSend("exchange","routingKey",message);
    }
}

消费消息

package com.xiaokai.listener;

import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

/**
 * Author:yang
 * Date:2024-10-15 15:11
 */
@Component
public class MessageListener {

    @RabbitListener(queues = "queue")
    public void processMessage(String message) {
        System.out.println("Received message: " + message);
    }

}
;