RabbitMQ---work消息模型

320 阅读2分钟

这是我参与更文挑战的第5天,活动详情查看: 更文挑战

work消息模型

image.png

官方翻译:工人之间分配任务(竞争者模型)

上一篇我们是一个生产者一个消费者,这一篇我们创建work,在多个消费者之间分配任务。

工作队列,又名任务队列,避免执行资源密集型任务时,必须等到执行结束,我们把消息发到队列,消费者获取消息并消费,多个消费者的时候并行执行,但是一个消息只能被消费一次。

p: 生产者 负责生产消息
c1:消费者1 
c2:消费者2

c1与c2相比处理消息更快一点

生产者

public class Producer_HelloWorld {
    public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {
        //1.创建连接工厂
        ConnectionFactory connectionFactory = new ConnectionFactory();
        //2.设置参数
        connectionFactory.setHost("192.168.145.3");
        connectionFactory.setPort(5672);
        connectionFactory.setVirtualHost("/zhaojin");
        connectionFactory.setUsername("zhaojin");
        connectionFactory.setPassword("zhaojin");
        //3.创建连接
        Connection connection = connectionFactory.newConnection();
        //4.创建 channel
        Channel channel = connection.createChannel();
        //5.创建queue
        channel.queueDeclare("hello_world",true,false,false,null);
        //6.发送
        for (int i = 0; i < 50; i++) {
            String bady ="hello RabbitMQ 第"+i+"次";
            channel.basicPublish("","hello_world",null,bady.getBytes());
            System.out.println("生产者发送消息"+bady);
        }
        //7.释放资源
        channel.close();
        connection.close();
    }
}

消费者1

public class c1 {
    public static void main(String[] args) throws IOException, TimeoutException {
        //1.创建连接工厂
        ConnectionFactory connectionFactory = new ConnectionFactory();
        //2.设置参数
        connectionFactory.setHost("192.168.145.3");
        connectionFactory.setPort(5672);
        connectionFactory.setVirtualHost("/zhaojin");
        connectionFactory.setUsername("zhaojin");
        connectionFactory.setPassword("zhaojin");
        //3.创建连接
        Connection connection = connectionFactory.newConnection();
        //4.创建 channel
        Channel channel = connection.createChannel();
        channel.queueDeclare("hello_world",true,false,false,null);
        //6.接受消息
        Consumer consumer = new DefaultConsumer(channel){
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                System.out.println("c1消费消息: "+new String(body));
                //手动ack
                channel.basicAck(envelope.getDeliveryTag(),false);
            }
        };
        channel.basicConsume("hello_world",false,consumer);
    }
}

消费者2

public class c2 {
    public static void main(String[] args) throws IOException, TimeoutException {
        //1.创建连接工厂
        ConnectionFactory connectionFactory = new ConnectionFactory();
        //2.设置参数
        connectionFactory.setHost("192.168.145.3");
        connectionFactory.setPort(5672);
        connectionFactory.setVirtualHost("/zhaojin");
        connectionFactory.setUsername("zhaojin");
        connectionFactory.setPassword("zhaojin");
        //3.创建连接
        Connection connection = connectionFactory.newConnection();
        //4.创建 channel
        Channel channel = connection.createChannel();
        channel.queueDeclare("hello_world",true,false,false,null);
        //6.接受消息
        Consumer consumer = new DefaultConsumer(channel){
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                System.out.println("c2消费消息 :"+new String(body));
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //手动ack
                channel.basicAck(envelope.getDeliveryTag(),false);
            }
        };
        channel.basicConsume("hello_world",false,consumer);
    }
}

设置了消费者2暂停1m来表示消费速度,然后同时打开c1c2,再打开生产者发送50条消息。看控制台运行情况。

image.png

image.png 虽然都消费了25条消息,实现了任务的分发,但是消费者1处理任务快,处理结束他一直处于空闲状态,但是两个人处理的消息是一样多的,这样不好,要的是处理快的人多处理消息。怎么实现呢,我们可以设置告诉MQ一次性不要给一个消费者发送多余一条的消息,不要向正再工作的人发消息,知道ack确认了再发,相反把消息发给干活快的人。

 //设置同时只处理一条
        channel.basicQos(1);

再次运行,可以看到能者处理了大部分分的工作。

image.png

image.png