RabbitMq——延迟队列

延迟队列:用于存放需要在指定时间后(TTL)被执行的消息的队列,延迟队列消息过期后会被存放到死信队列,消费者不断对死信队列进行消费。

TTL:消息存活的最大时间,单位为毫秒,在TTL时间内,若消息未被消费,则会成为死信。

延迟队列使用场景,如:

①订单在指定时间内未支付,则要自动取消订单;

②用户退款,商家在指定时间未回复,则发送消息提醒商家;

③预定会议后,在会议开始前10分钟i提醒参会人员参会;

④外卖订单配送要快超时,提醒配送员。

 

案例:一个生产者发送一条消息分给一个ttl为10s的延迟队列和一个ttl为40s的延迟队列,如下图:

RabbitMq——延迟队列_第1张图片

 

1、获取连接信道工具类RabbitUntils类,同时需要启动rabbitmq服务,以及关闭linux防火墙

//连接工厂,创建信道工具类
public class RabbitUtils {
    // 得到一个连接的 channel
    public static Channel getChannel() throws Exception {
        // 创建一个连接工厂
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("192.168.23.129");
        factory.setUsername("user");
        factory.setPassword("123");
        Connection connection = factory.newConnection();
        Channel channel = connection.createChannel();
        return channel;
    }
}

 2、创建生产者发送消息

        (1)调用工具类获取信道连接,声明普通交换机,类型为direct;

      (2)调用basicPublish(交换机,路由,其他参数,消息体)方法发送消息给消费者;

      (3)调用System.currentTimeMillis()获取本地时间,记录发送消息时的时间。

public class Producer {

    private final static String NORMAL_EXCHANGE="normal_exchange";

    public static void main(String[] args) throws Exception {
        //获取信道连接
        Channel channel = RabbitUtils.getChannel();
        //声明交换机
        channel.exchangeDeclare(NORMAL_EXCHANGE, BuiltinExchangeType.DIRECT);
        //消息体
        String messageA="赶快支付订单,队列为queueA";
        String messageB="赶快支付订单,队列为queueB";
        //发送消息给queueA
        channel.basicPublish(NORMAL_EXCHANGE,"NA",null,messageA.getBytes("UTF-8"));
        //发消息给queueB
        channel.basicPublish(NORMAL_EXCHANGE,"NB",null,messageB.getBytes("UTF-8"));
        System.out.println("生产者发送消息:"+messageA+",当前时间为:"+new SimpleDateFormat("yyyy年MM月dd日 HH时:mm分:ss秒").format(System.currentTimeMillis()));
        System.out.println("生产者发送消息:"+messageB+",当前时间为:"+new SimpleDateFormat("yyyy年MM月dd日 HH时:mm分:ss秒").format(System.currentTimeMillis()));
    }
}

3、创建消费者消费死信队列中的消息

        (1)获取信道,声明死信交换机和死信队列;

        (2)调用queueDeclare(队列名,是否持久化,是否只供·一个消费者,是否自动删除,其他参数)声明队列queueA,创建map集合,设置ttl过期时间为10s,消息过期后的死信交换机,以及延迟队列与死信交换机的路由;

        (3)调用queueDeclare(队列名,是否持久化,是否只供·一个消费者,是否自动删除,其他参数)声明队列queueB,修改map集合参数,设置ttl过期时间为40s,消息过期后的死信交换机,以及延迟队列与死信交换机的路由;

        (4)绑定队列A与普通交换机,队列B与普通交换机,死信队列与死信交换机;

        (5)调用basicConsumer(队列,是否自动应答,成功回调函数,失败回调函数)接收消息,记录接收消息的本地时间。

public class Consumer {
    //队列A,B名字
    private final static String QUEUEA="queueA";
    private final static String QUEUEB="queueB";
    private final static String NORMAL_EXCHANGE="normal_exchange";
    //死信队列,交换机名
    private final static String QUEUED="queueD";
    private final static String DEAD_EXCHANGE="dead_exchange";

    //消费死信队列消息消费者
    public static void main(String[] args) throws Exception {
        //获取连接
        Channel channel = RabbitUtils.getChannel();

        //声明死信队列和死信交换机
        channel.exchangeDeclare(DEAD_EXCHANGE, BuiltinExchangeType.DIRECT);
        channel.queueDeclare(QUEUED,false,false,false,null);

        //声明队列A
        Map argument=new HashMap<>();
        //设置ttl为10s
        argument.put("x-message-ttl",10000);
        //设置死信交换机
        argument.put("x-dead-letter-exchange",DEAD_EXCHANGE);
        //设置死信交换机与路由
        argument.put("x-dead-letter-routing-key","DD");
        channel.queueDeclare(QUEUEA,false,false,false,argument);

        //声明队列B
        //设置ttl为40s
        argument.put("x-message-ttl",40000);
        channel.queueDeclare(QUEUEB,false,false,false,argument);

        //绑定队列A与交换机,队列B与交换机
        channel.queueBind(QUEUEA,NORMAL_EXCHANGE,"NA");
        channel.queueBind(QUEUEB,NORMAL_EXCHANGE,"NB");
        //绑定死信队列与死信交换机
        channel.queueBind(QUEUED,DEAD_EXCHANGE,"DD");

        //接受消息成功回调
        DeliverCallback deliverCallback=(consumerTag,message)->{
            System.out.println("接收到消息:"+new String(message.getBody(),"UTF-8")+",当前时间为:"+new SimpleDateFormat("yyyy年MM月dd日 HH时:mm分:ss秒").format(System.currentTimeMillis()));
        };

        //消费死信队列消息
        channel.basicConsume(QUEUED,true,deliverCallback,consumerTag->{});

    }
}

4、生产者给队列A,B发送对应消息,测试如下

队列A的消息在10s后被消费,队列B的消息在40s后被消费,测试成功

RabbitMq——延迟队列_第2张图片

RabbitMq——延迟队列_第3张图片 

上面设置ttl在队列中设置,这样每次有需求都需要设置一个ttl延迟队列,需要设置延迟队列过多,我们可以通过添加一个队列C,此处队列C不设置ttl属性,通过生产者发送带有ttl时间的消息,即可优化,如下图:

RabbitMq——延迟队列_第4张图片

 

 

你可能感兴趣的:(rabbitmq,java)