RabbitMq延迟队列小Demo

一. 什么是延迟队列?

从字面意思上来看,延迟其实就是不会立即执行的会拖拖拉拉的感觉。就是在队列中的消息不会立刻被消费,而是需要等待一定的时间才会被消费。

二. 延迟队列的两种实现方式?

2.1 通过死信队列的方式

这种方式通过给消息或者队列设置TTL过期时间,如果说在设置的时间内该消息还没有被消费的话,那么就变成了"死消息",就进入我们预设的死信队列。

架构流程图:

 上面图大概意思就是消费者发送消息并且设置过期时间到交换机,交换机通过routingkey转发到Q1,因为没有消费者,所以会等待消息过期后进入exchange2,死信交换机将这条消息转发到队列,被消费者消费,至此完成了简单的延迟队列的流程。

2.2 利用交换机插件

使用插件的方式就简单很多了,我们直接到官网上下载对应的插件。

插件名:`rabbitmq-delayed-message-exchange`

下载地址:https://github.com/rabbitmq/rabbitmq-delayed-message-exchange/releases

2.2.1 将下载的插件安装到rabbitmq中

这儿图方便直接使用docker,下载插件以后,放到服务器上通过如下命令进行插件安装:

1. 前提是docker已经安装,并且运行了rabbitmq容器。

docker cp /home/rabbitmq_delayed_message_exchange-3.11.1.ez rabbitmq:/plugins

2. 执行完成以上命令以后,进入容器安装插件

docker exec -it 容器名 /bin/bash

3. 进入rabbitmq容器的plugins目录

4. 执行如下命令安装插件

rabbitmq-plugins enable rabbitmq_delayed_message_exchange

如果一切顺利的话,插件安装成功,重启rabbitmq容器

docker xxxx restart

5. 访问rabbit管理页面

在exchange一栏去看交换机类型,如果有红色矩形的内容存在,那么插件安装成功。

三 小Demo练习

这儿主要使用的是插件的方式,因为使用死队列的方式具有局限性且不太易于理解。这一个小Demo主要是模拟活动预约以后,在活动开始之前给预约活动的用户发一封邮件提醒参加预约的活动,算是一个很小很小的Demo了吧。

通过插件实现的延迟队列代码架构图:

3.1 搭建项目工程

就使用springboot工程吧!

1. 导入项目依赖

   <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.2</version>
    </parent>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-amqp</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.47</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <!--RabbitMQ 测试依赖-->
        <dependency>
            <groupId>org.springframework.amqp</groupId>
            <artifactId>spring-rabbit-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

2. 构建结构

 

3.2 构建队列和交换机

构建交换机、队列、绑定关系

@Configuration
public class DelayQueueConfig {
    private static final String DELAY_QUEUE = "delay.queue";
    private static final String DELAY_EXCHANGE = "delay.exchange";
    private static final String DELAY_ROUTING_KEY = "delay";

    // 声明队列
    @Bean
    public Queue delayQueue(){
        return new Queue(DELAY_QUEUE);
    }
    // 延迟交换机配置
    @Bean
    public CustomExchange customExchange(){
        Map<String, Object> args = new HashMap<>();
        // 声明交换机类型
        args.put("x-delayed-type", "direct");
        return new CustomExchange(DELAY_EXCHANGE, "x-delayed-message", true, false ,args);
    }
    // 绑定关系
    @Bean
    public Binding delayQueueBindingCustomExchange(
            @Qualifier("customExchange") CustomExchange customExchange,
            @Qualifier("delayQueue") Queue delayQueue
    ){
        return BindingBuilder.bind(delayQueue).to(customExchange).with(DELAY_ROUTING_KEY).noargs();
    }
}

生产者构建

@RestController
@RequestMapping("/delay")
public class RemindController {

    private static final String DELAY_EXCHANGE = "delay.exchange";
    private static final String DELAY_ROUTING_KEY = "delay";

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @GetMapping("/{activityName}")
    public String activityRemind(@PathVariable String activityName){
        // 延迟消息发送,简单模拟,10s
        rabbitTemplate.convertAndSend(DELAY_EXCHANGE, DELAY_ROUTING_KEY, activityName,
                correlationData ->{
                    correlationData.getMessageProperties().setDelay(10000);
                    return correlationData;
                }
        );
        return "ok";
    }
}

消费者构建

@Component
@Slf4j
public class DelayConsumer {
    // 当然也可以直接使用直接的方式绑定交换机
    @RabbitListener(queues = "delay.queue")
    public void delayListener(Message message){
        byte[] body = message.getBody();
        log.info("您预约参与的活动:{}, 还剩10分钟就开始了,记得参加哦!", new String(body));
    }
}

最后测试一下搭建成功没有:

浏览器访问:localhost:8080/delay/篮球活动

10秒钟以后延迟队列发来消息,说明demo搭建成功。

3.3 集成邮件发送功能

最后在集成一个邮件功能用于消息的发送!

首先呢,我是用的是网易邮箱,需要设置开启SMTP服务。

163网易免费邮-你的专业电子邮局

以上步骤完成以后,我们直接引入starter依赖,很方便的让我门操作邮箱:

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

yml配置文件

spring:
  rabbitmq:
    host: xxx
    username: xxx
    password: xxxx
  application:
    name: delay

  mail:
    #smtp服务主机
    host: smtp.163.com
    #服务协议
    protocol: smtp
    # 编码集
    default-encoding: UTF-8
    #发送邮件的账户
    username: xxxx
    #授权码,开启stmp服务后会弹出授权码
    password: xxxxx
    test-connection: true
    properties:
      mail:
        smtp:
          auth: true
          starttls:
            enable: true
            required: true

创建一个实体类:

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Email {
    // 他人的邮箱
    private String[] user;
    // 邮件的主题
    private String subject;
    // 邮件的内容
    private String content;
}

发送邮件的工具类:

@Component
public class EmailSendUtil {
    @Autowired
    private JavaMailSender mailSender;

    @Value("${spring.mail.username}")
    private String senderName;

    public void sendMail(Email email){
        SimpleMailMessage mailMessage = new SimpleMailMessage();
        mailMessage.setFrom(senderName);
        // 邮件接收人
        mailMessage.setTo(email.getUser());
        // 邮件主题
        mailMessage.setSubject(email.getSubject());
        // 邮件内容
        mailMessage.setText(email.getContent());
        mailSender.send(mailMessage);
    }
}

最后修改我们RabbitMq的消费者端:

@Component
@Slf4j
public class DelayConsumer {
    @Autowired
    private EmailSendUtil emailSendUtil;
    // 当然也可以直接使用直接的方式绑定交换机
    @RabbitListener(queues = "delay.queue")
    public void delayListener(Message message){
        byte[] body = message.getBody();
        log.info("您预约参与的活动:{}, 还剩10分钟就开始了,记得参加哦!", new String(body));
        String msg = String.format("您预约参与的活动:%s, 只有十分钟就要开始啦!", new String(body));
        Email email = new Email(new String[]{"test@qq.com", "test@qq.com"}, "活动开始提醒", new String(msg));
        emailSendUtil.sendMail(email);
    }
}

四. 小Demo效果

  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
RabbitMQ延迟队列是一种在需要延时处理消息的场景下非常有用的机制。在RabbitMQ 3.6.x之前,通常使用死信队列和TTL过期时间来实现延迟队列。然而,从RabbitMQ 3.6.x开始,官方提供了延迟队列的插件,可以方便地下载并安装到RabbitMQ中。\[1\] 使用RabbitMQ来实现延迟队列有许多优势。首先,RabbitMQ具有可靠的消息发送和投递机制,可以确保消息至少被消费一次,并且未被正确处理的消息不会被丢弃。其次,通过RabbitMQ集群的特性,可以解决单点故障问题,即使某个节点挂掉,延迟队列仍然可用,消息也不会丢失。\[2\] 当然,除了使用RabbitMQ延迟队列插件,还有其他一些选择来实现延迟队列,比如使用Java的DelayQueue、Redis的zset、Quartz或者Kafka的时间轮,每种方式都有其特点,根据具体场景选择适合的方式。\[2\] 要安装RabbitMQ延迟队列插件,可以从官网下载rabbitmq_delayed_message_exchange插件,并将其解压放置到RabbitMQ的插件目录中。然后,在RabbitMQ安装目录下的plugins目录中执行命令使插件生效,并重启RabbitMQ即可。\[3\] #### 引用[.reference_title] - *1* [RabbitMQ 延迟队列-对于入门来说可以快速上手](https://blog.csdn.net/u011433316/article/details/115003228)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [【RabbitMq04】延迟队列](https://blog.csdn.net/weixin_40964170/article/details/119214296)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值