rabbitmq_02_工作/任务队列(Work Queues)

一、模型图

Work queues,也被称为(Task queues),任务模型。

当消息处理比较耗时的时候,可能生产消息的速度会远远大于消息的消费速度。长此以往,消息就会堆积越来越多,无法及时处理。

此时就可以使用work 模型:让多个消费者绑定到一个队列,共同消费队列中的消息。

队列中的消息一旦消费,就会消失,因此任务是不会被重复执行的

  • P:生产者
  • C1:消费者1,获取消息,处理任务,假设速度较慢
  • C2:消费者2,获取消息,处理任务,假设速度快

二、rabbitmq的消息确认机制(ACK)

  • 默认情况下,RabbitMQ 会按顺序将每条消息发送给下一个消费者。平均而言,每个消费者都会收到相同数量的消息。
  • 消息一旦被消费者接收,无论是否消费成功,队列中的消息都会被删除。如果其中一个消费者处理遇到异常,会导致未被处理的消息丢失
  • 针对上述情况,rabbitMQ有一个消息确认机制。消费者获取消息后,会向rebbitMQ发送ACK,告知消息已经被接收

消息确认机制(ACK)分两种:

  • 自动ACK:消息一旦被接受,消费者自动ACK
  • 手动ACK:消息接收后,不会发送ACK,需要手动确认

由于消费者消费能力不同,希望能者多劳

三、代码实现

1、工具类

package com.java.study.rabbitmq.utils;

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

public class RabbitMQUtils {

    private static ConnectionFactory connectionFactory;
    static{
        //1.创建连接mq的连接工厂对象
        connectionFactory = new ConnectionFactory();
        //2.设置连接rabbitmq主机
        connectionFactory.setHost("192.168.8.222");
        //3.设置端口号
        connectionFactory.setPort(5672);
        //4.设置连接那个虚拟主机
        connectionFactory.setVirtualHost("/ems");
        //5.设置访问虚拟主机的用户名和密码
        connectionFactory.setUsername("ems");
        connectionFactory.setPassword("123");
    }

    public static Connection getConnections(){
        try{
            //6.获取连接
            return connectionFactory.newConnection();
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }

    public static void closeConnectionAndChannel(Channel channel,Connection connection){
        try {
            channel.close();
            connection.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

2、生产者

package com.java.study.rabbitmq.workqueue;

import com.java.study.rabbitmq.utils.RabbitMQUtils;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import org.junit.Test;

/**
 * 生产者 发送 消息
 */
public class Producer {

    private final static String QUEUE_NAME = "work";

    @Test
    public void sendMessages() throws Exception {

        //6.获取连接
        Connection connection = RabbitMQUtils.getConnections();
        //7.获取通道
        Channel channel = connection.createChannel();

        //8.通道绑定对应的消息队列
        //参数1:queue 队列名称,在队列不存在的情况下,自动创建
        //参数2:durable 用来定义队列的特性是否要持久化(消息不会持久化) true:持久化 false:不持久化
        //参数3:exclusive 是否独占队列 true:独占队列,false:不独占队列
        //参数4:autoDelete 是否在消费彻底完成(消费者停掉)后自动删除队列 true:自动删除,false:不自动删除
        //参数5:arguments 额外附加参数
        channel.queueDeclare(QUEUE_NAME, true, false, false, null);

        String message = "hello work queue";
        //9.发布消息
        //参数1:exchange 交换机名称
        //参数2:routingKey 队列名称(由这里具体指定发送到具体哪个队列中)
        //参数3:props 传递消息额外设置(由这里设置消息是否持久化,MessageProperties.PERSISTENT_TEXT_PLAIN:重启不会消失)
        //参数4:body 消息的具体内容
        for (int i = 1; i <= 10; i++) {
            channel.basicPublish("", QUEUE_NAME, null, (message+"====>:我是消息"+i).getBytes());
        }

        //关闭连接
        RabbitMQUtils.closeConnectionAndChannel(channel, connection);
    }
}

3、消费者1

package com.java.study.rabbitmq.workqueue;

import com.java.study.rabbitmq.utils.RabbitMQUtils;
import com.rabbitmq.client.*;

import java.io.IOException;

public class Consumer1 {
    private final static String QUEUE_NAME = "work";

    public static void main(String[] args) throws Exception {
        //6.获取连接
        Connection connection = RabbitMQUtils.getConnections();
        //7.获取通道
        Channel channel = connection.createChannel();

        //每个通道只能消费一个消息,在手动ACK下生效
        channel.basicQos(1);

        //8.通道绑定对应的消息队列
        //参数1:queue 队列名称,在队列不存在的情况下,自动创建
        //参数2:durable 用来定义队列的特性是否要持久化(消息不会持久化) true:持久化 false:不持久化
        //参数3:exclusive 是否独占队列 true:独占队列,false:不独占队列
        //参数4:autoDelete 是否在消费彻底完成(消费者停掉)后自动删除队列 true:自动删除,false:不自动删除
        //参数5:arguments 额外附加参数
        channel.queueDeclare(QUEUE_NAME, true, false, false, null);

        //9.消费消息
        //参数1:队列名称
        //参数2:开启消息的自动确认机制
        //参数3:消费消息时的回调接口
        channel.basicConsume(QUEUE_NAME, false, new DefaultConsumer(channel) {
            //参数1:consumerTag 消费者标签,用来标识消费者的,在
            //参数2:envelope 信封
            //参数3:properties 消息属性
            //参数4:body 消息队列中取出的消息
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("消费者1:" + new String(body));
                //参数1:手动确认消息标识
                //参数2:是否开启多个消息同时确认
                channel.basicAck(envelope.getDeliveryTag(),false);
            }
        });
    }
}

4、消费者2

package com.java.study.rabbitmq.workqueue;

import com.java.study.rabbitmq.utils.RabbitMQUtils;
import com.rabbitmq.client.*;

import java.io.IOException;

public class Consumer2 {
    private final static String QUEUE_NAME = "work";

    public static void main(String[] args) throws Exception {
        //6.获取连接
        Connection connection = RabbitMQUtils.getConnections();
        //7.获取通道
        Channel channel = connection.createChannel();

        //每个通道只能消费一个消息,在手动ACK下生效
        channel.basicQos(1);

        //8.通道绑定对应的消息队列
        //参数1:queue 队列名称,在队列不存在的情况下,自动创建
        //参数2:durable 用来定义队列的特性是否要持久化(消息不会持久化) true:持久化 false:不持久化
        //参数3:exclusive 是否独占队列 true:独占队列,false:不独占队列
        //参数4:autoDelete 是否在消费彻底完成(消费者停掉)后自动删除队列 true:自动删除,false:不自动删除
        //参数5:arguments 额外附加参数
        channel.queueDeclare(QUEUE_NAME, true, false, false, null);


        //9.消费消息
        //参数1:队列名称
        //参数2:消息的自动确认机制 true:消费者自动向rabbitmq确认消息消费(拿到即确认,遇到异常消息丢失) false:手动确认
        //参数3:消费消息时的回调接口
        channel.basicConsume(QUEUE_NAME, false, new DefaultConsumer(channel) {
            //参数1:consumerTag 消费者标签,用来标识消费者的,在
            //参数2:envelope 信封
            //参数3:properties 消息属性
            //参数4:body 消息队列中取出的消息
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                System.out.println("消费者2:" + new String(body));
                //参数1:手动确认消息标识
                //参数2:是否开启多个消息同时确认
                channel.basicAck(envelope.getDeliveryTag(),false);
            }
        });
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值