RabbitMQ

目录

一、MQ相关概念 

1.1 使用MQ的作用:

1.2 MQ选择:

二、Hello World实战

2.1 Demo

2.2 消息应答

2.3 消息重新入队

2.4 RabbitMQ持久化

队列持久化

消息持久化

2.5 发布确认(重点)

四、交换机

4.1 Fanout:扇出(广播)

4.2 Direct交换机

5、Topic

三、死信队列

实战逻辑图

 3.1 消息TTL过期

3.2 队列长度限制

四、延迟队列 

一、MQ相关概念 

MQ(message queue),本质是一个队列FIFO先进先出;

应用场景:12306购票、淘宝秒杀的时候、嘀嘀打车等;

1.1 使用MQ的作用:

1、流量削峰;

原来需要再很短的时间内去请求数据库,使用队列之后把请求的时间拉长;

2、解耦:

减少A系统和其他系统之间的直接联系,其他系统需要消息,直接去队列中按照相应规则取数据,而不用取更改A系统中的代码;减少和A系统之间的关联;

3、异步处理

同步:当我在处理的时候其他进程不能进来;

异步:当我在处理的时候,其他进程可以进入,提高了响应的速度;

1.2 MQ选择:

  • 大量数据的互联网服务的数据收集业务,如果有日志采集功能,首选Kafka;
  • 0消息丢失,天生就是为金融互联网领域而生,适用于高并发场景;
  • 数据量没有那么大使用RabbitMQ,并且RabbitMQ管理起来非常方便,可靠性高;

          RabbitMQ:

1、支持多语言、多平台;

2、采用erlang语言编写,天生具有高并发的优点;

3、微秒级的时效性;

Channel:作为轻量级的Connection极大减少了操作系统建立TCP connection的开销;

 

二、Hello World实战

2.1 Demo

生产者

package whut.zyf.test01;


import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;

//生产者
public class Producer {

    private static final String QUEUE_NAME="hello";
    public static void main(String[] args) throws Exception {
         //1、首先要创建一个连接
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("192.168.44.101");
        factory.setUsername("admin");
        factory.setPassword("123");
        Connection connection = factory.newConnection();

        //2、得到一个channel 为了减少tcp连接的开销
        Channel channel = connection.createChannel();

        //3、声明一个队列
        /**
         * 第一个参数:队列的名称
         * 第二个参数:队列是否持久化
         * 第三个参数:是否只让一个消费者独自消费(排它)
         * 第四个参数:消费者断开连接之后,是否自动删除该队列
         * 第五个参数:代表的是其他参数(死信队列)
         */
        channel.queueDeclare(QUEUE_NAME,false,false,false,null);

        //4、发送消息
        /**
         * 第一个参数:交换机的名称    “ ”空字符串代表默认的交换机
         * 第二个参数:路由的key     也就是发送给哪个队列
         *           默认采用队列名称作为路由key,发送的消息就会被路由到对应的队列中
         * 第三个参数:其他配置参数  (比如设置消息的过期时间)
         * 第四个参数:发送消息内容
         */
        String message = "hello word";
        channel.basicPublish("",QUEUE_NAME,null,message.getBytes());
        System.out.println("消息发送完成");

        channel.close();
        connection.close();

    }
}

第二种写法,可以不用使用close,因为Connection和channel都继承了AutoCloseable 

package whut.zyf.test01;


import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;

//生产者
public class Producer02 {

    private static final String QUEUE_NAME="hello";
    public static void main(String[] args) throws Exception {
         //1、首先要创建一个连接
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("192.168.44.101");
        factory.setUsername("admin");
        factory.setPassword("123");
        //Connection和channel都继承了AutoCloseable接口,说明这种接口就可以不用显示的调用close方法
        try(Connection connection = factory.newConnection();Channel channel = connection.createChannel();) {
            channel.queueDeclare(QUEUE_NAME,false,false,false,null);
            String message = "hello word";
            channel.basicPublish("",QUEUE_NAME,null,message.getBytes());
            System.out.println("消息发送完成");
        }
    }
}

消费者

package whut.zyf.test01;

import com.rabbitmq.client.*;


//消费者
public class Consumer {

    private static final String QUEUE_NAME="hello";

    public static void main(String[] args) throws Exception {
        //1、消费者要想获取队列中的连接,那么首先也要先创建连接
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("192.168.44.101");
        factory.setUsername("admin");
        factory.setPassword("123");
        Connection connection = factory.newConnection();
        //2、创建channel;
        Channel channel = connection.createChannel();
        System.out.println("消费者启动等到消费");
        //消费者需要一直消费消息,所以不需要断开连接
        /**
         * 队列推送消息给消费者的时候,如何消费消息
         * consumerTag:消费者的标记
         * delivery:传递给消费者的传递内容;
         */
        DeliverCallback deliverCallback = (consumerTag,delivery) -> {
            //消费者的信息,也就是是谁消费的
            System.out.println(consumerTag);
            String receivedMessage = new String(delivery.getBody());
            System.out.println("消费者接收到的消息:" + receivedMessage);
            System.out.println("发送的第几个消息:"+delivery.getEnvelope().getDeliveryTag());
        };
        /**
         * 消费者取消消费的回调接口
         */
        CancelCallback cancelCallback = (consumerTag) -> {
            System.out.println(consumerTag + "消费者取消消费消息");
        };

        /**
         * 消费者消费队列里面的消息
         * 第一个参数:队列名称
         * 第二个参数:是否采用自动应答(也就是相当于收快递的时候,是自动签收还是手动签收)
         * 第三个参数:队列推送消息给消费者的时候,如何消费消息;
         * 第四个参数:消费者取消消费消息的时候,回调接口;
         */
        channel.basicConsume(QUEUE_NAME,true,deliverCallback,cancelCallback);
    }
}

2.2 消息应答

防止消费者在消费消息的时候,消息丢失

手动应答:可以防止消息的丢失

        DeliverCallback deliverCallback = (var1, var2) -> {
            String receivedMessage = new String(var2.getBody());
            System.out.println("C2消费者接收到的消息" + receivedMessage);
//            channel.basicAck();
//            channel.basicNack();
//            channel.basicReject();
        };

如果将自动应答设置为false,可以再deliverCallback中,使用channel的三个方法,传入相应的参数,采取不同的应答模式,和消息拒绝策略;

2.3 消息重新入队

 当C1在处理消息的时候,还没有处理完,断开了连接,这个时候消息应该如何处理?

        该消息会重新入队,然后发送给当前活跃的存活的消费者;

2.4 RabbitMQ持久化

持久化是防止,生产者在生产消息的时候,消息不丢失

队列持久化

在创建队列的时候进行指定:

boolean durable = true;
        channel.queueDeclare(QUEUE_NAME,durable,false,false,null);

保证队列不丢失, 再对队列使用持久化之后,不可以再将其变为非持久化,除非删掉重新创建;

消息持久化

在发送消息的时候进行指定:MessageProperties.PERSTENT_TEXT_PLAIN;

 channel.basicPublish("",QUEUE_NAME, MessageProperties.PERSISTENT_TEXT_PLAIN,message.getBytes());

如果传了一个很大的数据,比如2G,如果在持久化的过程中RabbitMQ宕机了怎么办?

        可以使用更强力的持久化策略;

2.5 发布确认(重点)

发布确认可以解决数据在持久化过程中遇到RabbitMQ宕机的情况;

单个发布确认

缺点:吞吐量低;

//单个消息发布确认
    public static void publishMessageIndividual() throws Exception {
        Channel channel = RabbitMqUtils.getChannel();

        String queueName = UUID.randomUUID().toString();
        channel.queueDeclare(queueName,false,false,false,null);
        //开启发布确认,目的就是为了发送消息更加安全
        channel.confirmSelect();

        long begin = System.currentTimeMillis();
        for (int i = 0;i < MESSAGE_COUNT;i++){
            String message = "消息";
            channel.basicPublish("",queueName,null,message.getBytes());
            boolean flag = channel.waitForConfirms();
            if (flag){
                System.out.println("broker已经收到消息");
            }
        }
        long end = System.currentTimeMillis();
        System.out.println(end - begin);
    }

批量发布确认

批量操作缺点:因为不知道是这一批中的哪一个消息没有确认,所以需要对这一批全部进行重新发送,这样就会导致重复消费;

//批量消息发布确认
    public static void publishMessageBatch() throws Exception {
        Channel channel = RabbitMqUtils.getChannel();
        String queueName = UUID.randomUUID().toString();
        channel.queueDeclare(queueName,false,false,false,null);
        //开启发布确认,目的就是为了发送消息更加安全
        channel.confirmSelect();
        //要做批量处理,首先得知道批次大小是多少
        //定义一个多少个消息作为批量的值;
        int batchSize = 50;
        //定义一个当前已经发送多少个未确认的消息
        int outstandingMessageCount=0;
        long begin = System.currentTimeMillis();
        for (int i = 0;i < MESSAGE_COUNT;i++){
            String message = "消息" + i;
            channel.basicPublish("",queueName,null,message.getBytes());
            outstandingMessageCount++;
            if (batchSize == outstandingMessageCount){
                boolean flag = channel.waitForConfirms();
                if (flag){
                    System.out.println("broker已经收到消息");
                    outstandingMessageCount=0;
                }
            }
        }
        //对于无法整除的情况,比如120个消息,还剩余的20个就通过下面的代码进行处理
        if (outstandingMessageCount > 0){
            boolean flag = channel.waitForConfirms();
            if (flag){
                System.out.println("broker已经收到消息");
            }
        }
        long end = System.currentTimeMillis();
        System.out.println(end - begin);
    }

异步发布确认

逻辑图

 //异步发布消息确认
    public static void publishMessageAsync() throws Exception {
        Channel channel = RabbitMqUtils.getChannel();

        String queueName = UUID.randomUUID().toString();
        channel.queueDeclare(queueName,false,false,false,null);
        //开启发布确认,目的就是为了发送消息更加安全
        channel.confirmSelect();

        //线程安全的一个map:
        // ConcurrentSkipListMap:可以将序号和消息进行关联:
        // 只需给定序号,就会把《=当前序号的值作为一个map,提取出来;
        ConcurrentSkipListMap<Long, String> outstandingConfirms = new ConcurrentSkipListMap<>();
        //异步发布消息确认,需要一个监听器
        /**
         * 1、sequenceNumber 当前消息序号;
         * 2、multiple 处理一个还是多个消息;
         *         true:多个消息
         *         false:单个消息
         */
        ConfirmCallback ackCallback = (sequenceNumber, multiple) -> {
            //判断是批处理韩式单个处理
            if (multiple){
                //这个时候吧小于sequenceNumber的消息都从hashmap中删除
                //获取序号小于等于sequenceNumber的数据
                ConcurrentNavigableMap<Long, String> headMap = outstandingConfirms.headMap(sequenceNumber);
                //删除
                headMap.clear();
            }else {
                //只签收当前sequenceNumber的消息
                outstandingConfirms.remove(sequenceNumber);
            }
        };

        //如果说没有收到消息
        ConfirmCallback nackCallback = (sequenceNumber, multiple) -> {
            if (multiple){
                String message = outstandingConfirms.get(sequenceNumber);
                System.out.println(sequenceNumber +  "需要重新发送");
            }else {
                System.out.println(sequenceNumber +  "需要重新发送");
            }
        };
        //监听器:收到消息或者没有收到消息回调
        channel.addConfirmListener(ackCallback,nackCallback);


        long begin = System.currentTimeMillis();
        for (int i = 0;i < MESSAGE_COUNT;i++){
            String message = "消息";
            //将消息添加到hashmap中
            //channel.getNextPublishSeqNo():获取序号从1开始
            outstandingConfirms.put(channel.getNextPublishSeqNo(),message);

            channel.basicPublish("",queueName,null,message.getBytes());

        }
        long end = System.currentTimeMillis();
        System.out.println("异步处理时间 =" + (end - begin));
    }

四、交换机

临时队列:一旦消费者断开连接,队列就会被自动删除;

绑定(binding):让交换机和队列之间简历连接

默认交换机 

4.1 Fanout:扇出(广播)

实战

生产者:

package whut.zyf.test04;

import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import whut.zyf.utils.RabbitMqUtils;

import java.util.Scanner;

public class Task04 {

    private static String EXCHANGE_NAME="logs";
    public static void main(String[] args) throws Exception {
        Channel channel = RabbitMqUtils.getChannel();
        //声明一个交换机
        /**
         * 第一个是交换机的名称;
         * 第二个是交换机的类型;
         */
        channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.FANOUT);

        System.out.println("等待输入消息:..........................");
        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNext()){
            String message = scanner.nextLine();
            channel.basicPublish(EXCHANGE_NAME,"",null,message.getBytes());
            System.out.println("消息发送完成:" + message);
        }
    }
}

消费者_01

package whut.zyf.test04;

import com.rabbitmq.client.CancelCallback;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.ConsumerShutdownSignalCallback;
import com.rabbitmq.client.DeliverCallback;
import whut.zyf.utils.RabbitMqUtils;

public class ReceiveLog01 {
    private static String EXCHANGE_NAME="logs";
    public static void main(String[] args) throws Exception {
        Channel channel = RabbitMqUtils.getChannel();
        System.out.println("消费者等待消费消息");
        //创建临时队列
        /**
         * 临时队列:名字随机,消费者只要和队列断开连接,就会自动删除
         */
        String queueName = channel.queueDeclare().getQueue();
        //吧队列和交换机进行绑定
        channel.queueBind(queueName,EXCHANGE_NAME,"");

        System.out.println("ReceiveLogs01消费者,把接收到的消息打印在控制台...................");

        DeliverCallback deliverCallback = (consumerTag,delivery) -> {
            String receivedMessage = new String(delivery.getBody());
            System.out.println("ReceiveLogs01消费者接收到的消息:" + receivedMessage);
        };

        CancelCallback cancelCallback = (consumerTag) -> {
            System.out.println(consumerTag + "消费者取消消费消息");
        };

        channel.basicConsume(queueName,true,deliverCallback,cancelCallback);

    }
}

消费者_02

package whut.zyf.test04;

import com.rabbitmq.client.CancelCallback;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.DeliverCallback;
import org.apache.commons.io.FileUtils;
import whut.zyf.utils.RabbitMqUtils;

import java.io.File;

public class ReceiveLog02 {
    private static String EXCHANGE_NAME="logs";
    public static void main(String[] args) throws Exception {
        Channel channel = RabbitMqUtils.getChannel();
        System.out.println("消费者等待消费消息");
        //创建临时队列
        /**
         * 临时队列:名字随机,消费者只要和队列断开连接,就会自动删除
         */
        String queueName = channel.queueDeclare().getQueue();
        //吧队列和交换机进行绑定
        channel.queueBind(queueName,EXCHANGE_NAME,"");

        System.out.println("ReceiveLogs02消费者,把接收到的消息存储在磁盘...................");

        DeliverCallback deliverCallback = (consumerTag,delivery) -> {
            String receivedMessage = new String(delivery.getBody());
            File file = new File("F:\\JavaProjects\\RabbitMQ\\log.txt");
            FileUtils.writeStringToFile(file,receivedMessage,"UTF-8",true);
            System.out.println("消息已经写入磁盘");
        };

        CancelCallback cancelCallback = (consumerTag) -> {
            System.out.println(consumerTag + "消费者取消消费消息");
        };

        channel.basicConsume(queueName,true,deliverCallback,cancelCallback);

    }
}

4.2 Direct交换机

Direct只关注他绑定的某一类型或某一些消息,比如我只想让错误日志进入某个队列中进行处理;

实战

实战:

 生产者

package whut.zyf.test05;

import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import whut.zyf.utils.RabbitMqUtils;

import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
import java.util.Set;

public class EmitLogDirect {

    private static String EXCHANGE_NAME="direct_logs";
    public static void main(String[] args) throws Exception {
        Channel channel = RabbitMqUtils.getChannel();
        //声明一个交换机
        /**
         * 第一个是交换机的名称;
         * 第二个是交换机的类型;
         */
        channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.DIRECT);

        //创建多个bindingKey
        Map<String,String> bindingKeyMap = new HashMap<>();
        bindingKeyMap.put("info","普通info消息");
        bindingKeyMap.put("warning","警告warning信息");
        bindingKeyMap.put("error","错误error消息");
        bindingKeyMap.put("debug","调式debug消息");

        for (Map.Entry<String, String> bindingKeyEntry: bindingKeyMap.entrySet()){
            String routingKey = bindingKeyEntry.getKey();
            String message = bindingKeyEntry.getValue();
            channel.basicPublish(EXCHANGE_NAME,routingKey,null,message.getBytes());
            System.out.println("消息发送完成" + message);
        }

    }
}

消费者_01

package whut.zyf.test05;

import com.rabbitmq.client.CancelCallback;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.DeliverCallback;
import whut.zyf.utils.RabbitMqUtils;

public class ReceiveLog01 {

    private static String EXCHANGE_NAME="direct_logs";
    public static void main(String[] args) throws Exception {
        Channel channel = RabbitMqUtils.getChannel();
        System.out.println("消费者等待消费消息");
        String queueName = "console";
        channel.queueDeclare(queueName,false,false,false,null);
        //把队列和交换机进行绑定
        channel.queueBind(queueName,EXCHANGE_NAME,"info");
        channel.queueBind(queueName,EXCHANGE_NAME,"warning");

        System.out.println("ReceiveLogs01消费者,把接收到的消息打印在控制台...................");

        DeliverCallback deliverCallback = (consumerTag,delivery) -> {
            String receivedMessage = new String(delivery.getBody());
            String routingKey = delivery.getEnvelope().getRoutingKey();
            System.out.println("ReceiveLogs01消费者接收到的消息:" + receivedMessage);
            System.out.println("C1接收路由" + routingKey+ "........消息.........");
        };

        CancelCallback cancelCallback = (consumerTag) -> {
            System.out.println(consumerTag + "消费者取消消费消息");
        };

        channel.basicConsume(queueName,true,deliverCallback,cancelCallback);

    }
}

消费者_02

package whut.zyf.test05;

import com.rabbitmq.client.CancelCallback;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.DeliverCallback;
import org.apache.commons.io.FileUtils;
import whut.zyf.utils.RabbitMqUtils;

import java.io.File;

public class ReceiveLog02 {
    private static String EXCHANGE_NAME="direct_logs";
    public static void main(String[] args) throws Exception {
        Channel channel = RabbitMqUtils.getChannel();
        System.out.println("消费者等待消费消息");
        //创建临时队列
        /**
         * 临时队列:名字随机,消费者只要和队列断开连接,就会自动删除
         */
        String queueName = "disk";
        channel.queueDeclare(queueName,false,false,false,null);
        //吧队列和交换机进行绑定
        channel.queueBind(queueName,EXCHANGE_NAME,"error");

        System.out.println("ReceiveLogs02消费者,把接收到的消息存储在磁盘...................");

        DeliverCallback deliverCallback = (consumerTag,delivery) -> {
            String receivedMessage = new String(delivery.getBody());
            File file = new File("F:\\JavaProjects\\RabbitMQ\\direct_log.txt");
            FileUtils.writeStringToFile(file,receivedMessage,"UTF-8",true);
            String routingKey = delivery.getEnvelope().getRoutingKey();
            System.out.println("C2接收路由" + routingKey+ ".....消息............");
            System.out.println("消息已经写入磁盘");
        };

        CancelCallback cancelCallback = (consumerTag) -> {
            System.out.println(consumerTag + "消费者取消消费消息");
        };

        channel.basicConsume(queueName,true,deliverCallback,cancelCallback);

    }
}

5、Topic

和前面原理一样,支持通配符方式进行绑定,更加细致;

* :代表匹配一个单词;

# :0-多个单词

三、死信队列

由于某种原因导致队列中的消息无法被消费者消费——死信

装有死信消息的队列称为死信队列;

死信的来源:

  •         消息TTL过期
  •         队列达到最大长度
  •         消息被拒绝

实战逻辑图

 3.1 消息TTL过期

生产者

package whut.zyf.test07;

import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import whut.zyf.utils.RabbitMqUtils;

public class Producer {

    private static final String NORMAL_EXCHANGE_NAME = "normal_exchange";
    public static void main(String[] args) throws Exception {
        Channel channel = RabbitMqUtils.getChannel();

        channel.exchangeDeclare(NORMAL_EXCHANGE_NAME, BuiltinExchangeType.DIRECT);
        System.out.println("生产者等待发送消息");
        String message = "info";
        //给消息一个TTL时间,时间到期之后还没有被消费就进入死信;
        AMQP.BasicProperties properties = new AMQP.BasicProperties().builder().expiration("5000").build();
        channel.basicPublish(NORMAL_EXCHANGE_NAME,"zhangsan",properties,message.getBytes());
        System.out.println("消息发送完成");
    }
}

消费者

package whut.zyf.test07;

import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.DeliverCallback;
import whut.zyf.utils.RabbitMqUtils;

import java.util.HashMap;
import java.util.Map;

public class Consumer01 {

    private static final String NORMAL_QUEUE_NAME = "normal_queue";
    private static final String NORMAL_EXCHANGE_NAME = "normal_exchange";
    private static final String DEAD_QUEUE_NAME = "dead_queue";
    private static final String DEAD_EXCHANGE_NAME = "dead_exchange";

    public static void main(String[] args) throws Exception {
        Channel channel = RabbitMqUtils.getChannel();

        //死信队列
        channel.queueDeclare(DEAD_QUEUE_NAME,false,false,false,null);
        //死信交换机
        channel.exchangeDeclare(DEAD_EXCHANGE_NAME, BuiltinExchangeType.DIRECT);
        //死信队列和死信交换机之间的绑定关系
        channel.queueBind(DEAD_QUEUE_NAME,DEAD_EXCHANGE_NAME,"lisi");

        //正常队列和死信交换机的绑定关系
        //将deadLetterParams传到正常队列中,就完成了正常队列和死信交换机之间的绑定
        Map<String,Object> deadLetterParams = new HashMap<>();
        deadLetterParams.put("x-dead-letter-exchange",DEAD_EXCHANGE_NAME);
        deadLetterParams.put("x-dead-letter-routing-key","lisi");

        //声明一个正常队列
        channel.queueDeclare(NORMAL_QUEUE_NAME,false,false,false,deadLetterParams);
        //正常交换机
        channel.exchangeDeclare(NORMAL_EXCHANGE_NAME, BuiltinExchangeType.DIRECT);
        //正常队列和交换机绑定
        channel.queueBind(NORMAL_QUEUE_NAME,NORMAL_EXCHANGE_NAME,"zhangsan");

        DeliverCallback deliverCallback = (consumerTag,delivery) -> {
            String message = new String(delivery.getBody());
            System.out.println("消费者接收到的消息:" + message);
        };

        channel.basicConsume(NORMAL_QUEUE_NAME,true,deliverCallback,(consumerTag) -> {
            System.out.println(consumerTag+"消费者取消消费消息");
        });


    }
}

3.2 队列长度限制

//将deadLetterParams传到正常队列中,就完成了正常队列和死信交换机之间的绑定
        Map<String,Object> deadLetterParams = new HashMap<>();
        deadLetterParams.put("x-dead-letter-exchange",DEAD_EXCHANGE_NAME);
        deadLetterParams.put("x-dead-letter-routing-key","lisi");
        //给正常队列添加长度属性
        deadLetterParams.put("x-max-length",6); //正常队列的最大容纳长度

3.3 消息拒绝

采用手动应答,之后拒绝重新入队,消息就会进入死信队列

四、延迟队列 

场景:

1、订单在十分钟之内未支付则自动取消;

2、新创建的店铺,如果在十天内没有上传过商品,则自动发送消息提醒;

3、用户注册成功后,如果三天内没有登陆则进行短信提醒;

4、用户发起退款,如果三天内没有得到处理则通知相关运营人员;

5、预定会议后,需要在预定的时间内通知各个与会人员参与会议;

 队列TTL和消息TTL

消息是否过期需要到消费者那里去进行判断;

队列过期之后,不需要消费者进行判断,直接进入死信队列;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小馨java

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值