二十分钟带你速通RabbitMQ

一、RabbitMQ 概述

1. 定义

RabbitMQ 是基于 AMQP(高级消息队列协议)的开源消息代理和队列服务器。在分布式系统里,它负责在不同组件间传递消息,实现系统解耦、异步处理与流量削峰。

2. 应用场景

  • 系统解耦:电商系统中,订单系统和库存系统可通过 RabbitMQ 解耦。订单系统生成订单消息后发送到队列,库存系统从队列获取消息处理库存扣减。
  • 异步处理:用户注册时,发送注册邮件这类耗时操作可通过消息队列异步处理,用户注册成功后立即返回结果,邮件发送任务入队等待处理。
  • 流量削峰:秒杀活动中,大量用户请求先进入消息队列,系统按一定速率从队列取请求处理,避免系统因高流量崩溃。

二、RabbitMQ 核心概念

1. 生产者(Producer)

消息的发送方,将消息发送到 RabbitMQ 的交换器(Exchange)。

2. 消费者(Consumer)

消息的接收方,从 RabbitMQ 的队列(Queue)获取消息并处理。

3. 交换器(Exchange)

接收生产者消息,并按路由规则将消息路由到一个或多个队列。常见类型有:

  • 直连交换器(Direct Exchange):根据消息路由键(Routing Key)和绑定键(Binding Key)精确匹配来路由消息。
  • 扇形交换器(Fanout Exchange):将消息广播到所有绑定队列,不考虑路由键。
  • 主题交换器(Topic Exchange):依据消息路由键和绑定键的模式匹配规则路由,绑定键可用 *(匹配一个单词)和 #(匹配零个或多个单词)。
  • 头交换器(Headers Exchange):根据消息头部信息(Headers)决定路由。

4. 队列(Queue)

存储交换器路由过来的消息,供消费者获取处理。

5. 绑定(Binding)

交换器和队列的关联关系,通过绑定键将二者绑定,决定消息从交换器到队列的路由。

6. 虚拟主机(Virtual Host)

RabbitMQ 中的逻辑概念,用于隔离不同应用程序,每个虚拟主机有独立的交换器、队列和绑定。

三、RabbitMQ 安装与启动

1. Ubuntu 安装步骤

echo "deb https://packagecloud.io/rabbitmq/rabbitmq-server/ubuntu/ $(lsb_release -sc) main" | sudo tee /etc/apt/sources.list.d/rabbitmq.list
curl -fsSL https://packagecloud.io/rabbitmq/rabbitmq-server/gpgkey | sudo apt-key add -
sudo apt-get update
sudo apt-get install rabbitmq-server

2. 启动与管理

sudo systemctl start rabbitmq-server
sudo systemctl stop rabbitmq-server
sudo systemctl restart rabbitmq-server
sudo systemctl status rabbitmq-server

3. 启用管理界面

sudo rabbitmq-plugins enable rabbitmq_management

启用后,访问 http://localhost:15672,用默认用户名 guest 和密码 guest 登录。

四、基于 Spring Boot 使用 RabbitMQ(注解方式)

1. 项目准备

pom.xml 中添加依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-amqp</artifactId>
</dependency>

2. 配置文件

application.yml 配置:

spring:
  rabbitmq:
    host: localhost
    port: 5672
    username: guest
    password: guest

3. 生产者代码示例

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

@Service
public class RabbitMQProducer {
    @Autowired
    private RabbitTemplate rabbitTemplate;
    private static final String EXCHANGE_NAME = "directExchange";
    private static final String ROUTING_KEY = "directRoutingKey";

    public void sendMessage(String message) {
        rabbitTemplate.convertAndSend(EXCHANGE_NAME, ROUTING_KEY, message);
        System.out.println(" [x] Sent '" + message + "'");
    }
}

4. 消费者代码示例

import org.springframework.amqp.rabbit.annotation.*;
import org.springframework.stereotype.Service;

@Service
public class RabbitMQConsumer {
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(name = "directQueue", durable = "true"),
            exchange = @Exchange(name = "directExchange", type = "direct"),
            key = "directRoutingKey"
    ))
    public void receiveMessage(String message) {
        System.out.println(" [x] Received '" + message + "'");
    }
}

5. 测试代码

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class RabbitMQApplication implements CommandLineRunner {
    @Autowired
    private RabbitMQProducer producer;

    public static void main(String[] args) {
        SpringApplication.run(RabbitMQApplication.class, args);
    }

    @Override
    public void run(String... args) throws Exception {
        producer.sendMessage("Hello, RabbitMQ with Annotations!");
    }
}

五、RabbitMQ 高级特性

1. 消息确认机制

生产者确认
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class ConfirmProducer {
    @Autowired
    private RabbitTemplate rabbitTemplate;

    public void sendMessageWithConfirm(String message) {
        CorrelationData correlationData = new CorrelationData("1");
        rabbitTemplate.convertAndSend("directExchange", "directRoutingKey", message, correlationData);
        rabbitTemplate.setConfirmCallback((correlationData1, ack, cause) -> {
            if (ack) {
                System.out.println("Message sent successfully");
            } else {
                System.out.println("Message sent failed: " + cause);
            }
        });
    }
}
消费者确认
import org.springframework.amqp.rabbit.annotation.AcknowledgeMode;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Service;

@Service
public class ConfirmConsumer {
    @RabbitListener(queues = "directQueue", ackMode = AcknowledgeMode.MANUAL)
    public void receiveMessage(org.springframework.amqp.core.Message message,
                               com.rabbitmq.client.Channel channel) throws Exception {
        try {
            System.out.println("Received message: " + new String(message.getBody()));
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        } catch (Exception e) {
            channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, true);
        }
    }
}

2. 消息持久化

import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class PersistentConfig {
    public static final String PERSISTENT_QUEUE = "persistentQueue";
    public static final String PERSISTENT_EXCHANGE = "persistentExchange";
    public static final String PERSISTENT_ROUTING_KEY = "persistentRoutingKey";

    @Bean
    public Queue persistentQueue() {
        return new Queue(PERSISTENT_QUEUE, true);
    }

    @Bean
    public DirectExchange persistentExchange() {
        return new DirectExchange(PERSISTENT_EXCHANGE, true, false);
    }

    @Bean
    public Binding persistentBinding() {
        return BindingBuilder.bind(persistentQueue()).to(persistentExchange()).with(PERSISTENT_ROUTING_KEY);
    }
}

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

@Service
public class PersistentProducer {
    @Autowired
    private RabbitTemplate rabbitTemplate;

    public void sendPersistentMessage(String message) {
        rabbitTemplate.convertAndSend(PersistentConfig.PERSISTENT_EXCHANGE,
                PersistentConfig.PERSISTENT_ROUTING_KEY, message);
    }
}

3. 死信队列

当消息被拒绝(basicRejectbasicNack)且 requeuefalse、消息过期或队列达到最大长度时,消息会进入死信队列。

import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class DeadLetterConfig {
    public static final String NORMAL_QUEUE = "normalQueue";
    public static final String DEAD_LETTER_QUEUE = "deadLetterQueue";
    public static final String NORMAL_EXCHANGE = "normalExchange";
    public static final String DEAD_LETTER_EXCHANGE = "deadLetterExchange";
    public static final String NORMAL_ROUTING_KEY = "normalRoutingKey";
    public static final String DEAD_LETTER_ROUTING_KEY = "deadLetterRoutingKey";

    @Bean
    public Queue normalQueue() {
        return QueueBuilder.durable(NORMAL_QUEUE)
               .withArgument("x-dead-letter-exchange", DEAD_LETTER_EXCHANGE)
               .withArgument("x-dead-letter-routing-key", DEAD_LETTER_ROUTING_KEY)
               .build();
    }

    @Bean
    public Queue deadLetterQueue() {
        return new Queue(DEAD_LETTER_QUEUE, true);
    }

    @Bean
    public DirectExchange normalExchange() {
        return new DirectExchange(NORMAL_EXCHANGE, true, false);
    }

    @Bean
    public DirectExchange deadLetterExchange() {
        return new DirectExchange(DEAD_LETTER_EXCHANGE, true, false);
    }

    @Bean
    public Binding normalBinding() {
        return BindingBuilder.bind(normalQueue()).to(normalExchange()).with(NORMAL_ROUTING_KEY);
    }

    @Bean
    public Binding deadLetterBinding() {
        return BindingBuilder.bind(deadLetterQueue()).to(deadLetterExchange()).with(DEAD_LETTER_ROUTING_KEY);
    }
}

4. 延迟队列

可通过消息过期时间和死信队列实现。

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

@Service
public class DelayProducer {
    @Autowired
    private RabbitTemplate rabbitTemplate;

    public void sendDelayMessage(String message, long delay) {
        rabbitTemplate.convertAndSend(DeadLetterConfig.NORMAL_EXCHANGE,
                DeadLetterConfig.NORMAL_ROUTING_KEY, message, msg -> {
                    msg.getMessageProperties().setExpiration(String.valueOf(delay));
                    return msg;
                });
    }
}

六、RabbitMQ 监控与管理

1. 管理界面监控

通过 http://localhost:15672 可实时监控队列消息数量、消费者连接数、消息速率等信息。

2. 命令行工具监控

sudo rabbitmqctl list_queues
sudo rabbitmqctl list_connections
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值