RabbitMQ 概述

RabbitMQ 概述

1. 什么是 MQ

MQ (Message Queue), 即"消息队列". 从字面意思上看, 本质是个队列 (FIFO 先入先出), 只不过队列中存放的内容是消息 (message) 而已. 消息可以非常简单, 比如只包含文本字符串, JSON 等. 也可以很复杂, 比如内嵌对象. MQ多用于分布式系统之间进行通信.

系统之间的调用通常有两种方式:

  1. 同步通信

image-20250524101808497

直接调用对方的服务, 数据从一端发出后立即就可以达到另一端.

  1. 异步通信

image-20250524101945897

数据从一端发出后, 先进入一个容器进行临时存储. 达到某种条件后, 再由这个容器发送给另一端. 消息队列 MQ 就是容器的一种具体实现.

2. MQ 的作用

MQ主要工作是接收并转发消息, 在不同的应用场景下可以展现不同的作用.

(1) 异步解耦

在业务流程中: 一些操作非常耗时, 但是并不需要即时返回结果, 此时就可以借助 MQ 把这些操作异步化.

比如: 用户注册后发送注册短信或邮件通知, 可以作为异步任务处理, 而不必等待短信和邮件都发送完成后才告知用户注册成功.

再比如: 抽奖系统中, 状态扭转这个操作比较庞大, 但是我们并不需要等待所有活动, 奖品, 人员 的状态都扭转完成之后再通知给用户. 所以就引入了消息队列 MQ 将状态扭转操作进行异步化, 及时给用户返回中奖情况, 提高用户体验.

(2) 流量削峰

MQ 能够对突发的大量请求进行削峰, 保证消息消费方不会大量的请求冲垮.

比如秒杀或者促销活动, 可以使用 MQ 来控制流量, 将请求排队, 然后系统根据自己的处理能力逐步处理这些请求.

(3) 消息分发

当多个系统都需要获取同一数据时, 可以使用 MQ 进行消息分发. 比如支付成功后, 支付系统可以向 MQ 发送消息, 其他系统订阅队列中的支付消息, 而无需轮询数据库.

(4) 延迟通知

在需要在特定时间后发送通知的场景中, 可以使用 MQ 的延迟消息功能. 比如在电商平台中, 如果用户下单后一定时间内未支付, 可以使用延迟队列在超时后自动取消订单.

3. RabbitMQ 介绍

3.1 什么是 RabbitMQ

目前业界有很多 MQ 产品, 如 RabbitMQ, RocketMQ, Kafka 等. 也有直接用 Redis 充当消息队列的案例. 这些消息队列, 各有优势, 没有好与坏, 只有适合与不适合. 我们这里采用 RabbitMQ 来进行学习.

RabbitMQ 是采用 Erlang 语言实现, 遵循 AMQP (Advanced Message Queuing Protocol, “高级消息队列协议”) 的消息中间件, 它最初起源于金融系统领域, 为了在分布式系统中存储和转发消息而设计的.

[!TIP]

: 什么是 AMQP?

: AMQP (Advanced Message Queuing Protocol) 是一种消息队列协议, 它定义了客户端与消息中间件 (Broker) 之间的通信规范, 保证了应用程序之间的可靠消息传递.

3.2 RabbitMQ 核心概念

image-20250524103255280

image-20250310213744430

整个消息队列通信体系有三部分组成: Producer + Broker + Consumer. 其中, Broker 就是消息队列主体.

(1) Producer 生产者

是 RabbitMQ Server 的客户端, 向 RabbitMQ 发送消息. (发件人)

(2) Consumer 消费者

也是 RabbitMQ Server 的客户端, 从 RabbitMQ 接收消息. (收件人)

(3) Broker 消息队列服务器

RabbitMQ Server (RabbitMQ 服务器) 主要负责接收和转发消息. Broker 中又包括多个 Exchange, 多个 Queue.

生产和消费的基本流程:

  1. 生产者创建消息, 然后发到 RabbitMQ 中. 在实际应用中, 消息通常带有一定的标签, RabbitMQ 服务器中的 Exchange (交换机) 会根据标签进行路由, 把消息分配到相应队列.
  2. 消费者连接到 RabbitMQ 服务器, 就可以消费消息了. 消费者只收到消息, 并不知道消息的生产者是谁.

image-20250524104409706

(4) Exchange 交换机

message 到达 broker 的第一站. Exchange 起到了***消息路由的作用, 它负责接收生产者发送的消息, 并根据特定规则把消息路由到特定的 Queue 中***.

Exchange 根据类型和规则来确定如何转发接收到的消息. 类似于发快递之后, 物流公司根据地址来分派快递到不同的站点, 然后再送到收件人手里.

(5) Queue: 队列

队列是 RabbitMQ 的内部对象, 用于***存储消息***.

image-20250524103832491

注: 一个队列可以被多个消费者订阅 ; 一个消费者也可以订阅多个队列 (队列和消费者是多对多的关系)

image-20250524103846817

(6) Virtual host 虚拟主机

虚拟主机. 这是一个虚拟概念. 它为消息队列提供了一种逻辑上的隔离机制. 当多个不同的用户使用同一个RabbitMQ Server 提供的服务时, 可以虚拟划分出多个 Virtual host, 每个用户在自己的 vhost 创建 exchange/queue 等. 一个 BrokerServer 上可以存在多个 Virtual Host.

[!TIP]

Virtual host 和 MySQL 的 database 很相似, 主要作用都是**对不同业务环境进行隔离**. 一个MySQL服务器可以有多个database; 同样, 一个 RabbitMQ 服务器也可以有多个 Virtual host.

(7) Connection 和 Channel
  • Connection (连接) 是客户端和 RabbitMQ 服务器之间的一个 TCP 连接. 它负责传输客户端和服务器之间的所有数据.
  • Channel (通道), 又称信道. Channel 是在 Connection 之上的一个抽象层. 一个 Connection 可以有多个Channel, 消息的发送和接收都是基于 Channel 的. (“生产者使用 channel 发送消息 ; 消费者使用 channel 接收消息”).

image-20250524105055901

4. RabbitMQ 的使用

4.1 引入依赖

pom.xml:

        <dependency>
            <groupId>com.rabbitmq</groupId>
            <artifactId>amqp-client</artifactId>
            <version>5.20.0</version>
        </dependency>
4.2 生产者代码编写
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

public class ProducerDemo {
    public static void main(String[] args) throws IOException, TimeoutException {
        //1.建立连接

        //(1) IP
        //(2) 端口号
        //(3) 账号
        //(4) 密码
        //(5) 虚拟主机
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("120.53.237.101");
        factory.setPort(5672);
        factory.setUsername("admin");
        factory.setPassword("admin");
        factory.setVirtualHost("vhost1");
        Connection connection = factory.newConnection();

        //2.开启信道
        Channel channel = connection.createChannel();

        //3.声明交换机 (使用内置交换机)

        //4.声明队列
        /**
         * queueDeclare(String queue, boolean durable, boolean exclusive, boolean autoDelete,
         *              Map<String,Object> arguments)
         *  参数说明:
         *  queue:队列名称
         *  durable:可持久化
         *  exclusive:是否独占
         *  autoDelete:是否自动删除
         *  arguments:参数
         */
        channel.queueDeclare("hello", true, false, false, null);

        //5. 发送消息
        /**
         * basicPublish(String exchange, String routingKey, BasicProperties props, byte[] body)
         *  参数说明:
         *  exchange:交换机名称
         *  routingKey:路由标签. (对于内置交换机,routingkey和队列名称保持一致)
         *  props:属性配置
         *  body:消息
         */
        for (int i = 0; i < 10; i++) {
            String msg = "hello rabbitmq" + i;
            channel.basicPublish("", "hello", null, msg.getBytes());
            System.out.println("消息发送成功" + i);
        }


        //6. 资源释放
        channel.close();
        connection.close();
    }
}

4.3 消费者代码编写
import com.rabbitmq.client.*;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

public class ConsumerDemo {
    public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {
        //1. 创建连接
        ConnectionFactory connectionFactory = new ConnectionFactory();
        connectionFactory.setHost("120.53.237.101");
        connectionFactory.setPort(5672);
        connectionFactory.setUsername("admin");
        connectionFactory.setPassword("admin");
        connectionFactory.setVirtualHost("vhost1");
        Connection connection = connectionFactory.newConnection();
        //2. 创建Channel
        Channel channel = connection.createChannel();
        //3. 声明队列 (如果消费者要订阅的队列已经存在, 则可以省略)
        channel.queueDeclare("hello",true, false, false, null);
        //4. 消费消息
        /**
         * basicConsume(String queue, boolean autoAck, Consumer callback)
         * 参数说明:
         * queue: 队列名称
         * autoAck: 是否自动确认
         * callback: 接收到消息后, 执行的逻辑
         */
        DefaultConsumer consumer = new DefaultConsumer(channel){
            //从队列中收到消息, 就会执行的方法
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                System.out.println("接收到消息:"+ new String(body));
            }
        };

        channel.basicConsume("hello", true, consumer);

        //等待程序执行完成
        Thread.sleep(3000);

        //5. 释放资源
        channel.close();
        connection.close();
    }
}

4.4 快速使用

退出 erlang:

halt().

RabbitMQ 服务器默认端口号是 5672.

操作 rabbitmq 有三种方式:

  1. 通过代码来操作, 客户端和服务器建立连接(tcp连接) (5672 端口)
  2. 通过可视化管理界面操作 (15672 端口)
  3. 通过命令操作 (rabbitmqctl 命令)

使用哪个用户新创建虚拟机, 哪个用户就默认对该虚拟机有操作权限.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值