4-工作队列模式(Work Queues)

参考官方文档
rabbitmq版本:3.8.3
amqp-client版本:5.7.1

工作队列模式:一个生产者,一个消息队列,多个消费者,同样也称为点对点模式。

工作队列模式的最大特点就是有多个消费者,这样就不会因为处理耗时的任务导致MQ不可用。

4-工作队列模式(Work Queues)_第1张图片

默认情况下,rabbitmq将会按顺序派发每个任务给下一个消费者,平均而言,每个消费者将获得相同数量的消息,这种分发消息的方式称为轮询

1 基于java client代码示例

1.1 引入amqp-client依赖

<dependency>
    <groupId>com.rabbitmqgroupId>
    <artifactId>amqp-clientartifactId>
    <version>5.7.1version>
dependency>

1.2 生产者

/**
 * 生成者
 */
public class Producer {

    public static final String WORK_QUEUE = "work-queue";

    public static void main(String[] args) {
        // 1、创建连接工厂
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("192.168.99.100");
        factory.setPort(5672);
        factory.setUsername("admin");
        factory.setPassword("password");
        // 2、获取连接、通道
        try (Connection connection = factory.newConnection();
             Channel channel = connection.createChannel()) {
            // 3、声明发送消息的队列
            channel.queueDeclare(WORK_QUEUE, true, false, false, null);
            // 4、限制一次只分发一个消息给同一个消费者
            channel.basicQos(1);
            // 5、发送消息
            int count = 1;
            while (true) {
                String message = "Simple Queue Message, count = " + count;
                count++;
                channel.basicPublish("", WORK_QUEUE, null, message.getBytes());
                System.out.println("Send message: " + message);
                Thread.sleep(2000);
            }
        } catch (TimeoutException | IOException | InterruptedException e) {
            e.printStackTrace();
        }
    }
}

几点说明:

  • channel.queueDeclare(WORK_QUEUE, true, false, false, null);第二个参数置为true,表示设置队列为持久化队列,当rabbitmq崩溃之后,队列将被保存,当rabbitmq恢复之后,队列将会恢复,但是不是100%一定持久化。
  • channel.basicQos(1);设置一次只分发一个消息给同一个消费者,这样保证有多个消费者的时候不会其中一个一直在消费消息,而其他的消费者处于空闲状态。

1.3 多个消费者

/**
 * 多个消费者
 */
public class Consumers {
    // 启动两个消费者
    public static void main(String[] args) {
        // 消费者1
        new Thread(() -> {
            try {
                new Consumer(1).start();
            } catch (IOException | TimeoutException e) {
                e.printStackTrace();
            }
        }).start();

        // 消费者2
        new Thread(() -> {
            try {
                new Consumer(2).start();
            } catch (IOException | TimeoutException e) {
                e.printStackTrace();
            }
        }).start();
    }
}

/**
 * 消费者
 */
class Consumer {

    public static final String WORK_QUEUE = "work-queue";
    private int no = 0;

    public Consumer(int no) {
        this.no = no;
    }

    /**
     * 启动
     * @throws IOException
     * @throws TimeoutException
     */
    public void start() throws IOException, TimeoutException {
        // 1、创建连接工厂
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("192.168.99.100");
        factory.setPort(5672);
        factory.setUsername("admin");
        factory.setPassword("password");
        // 2、获取连接、通道
        Connection connection = factory.newConnection();
        Channel channel = connection.createChannel();
        // 3、声明监听的队列
        channel.queueDeclare(WORK_QUEUE, true, false, false, null);
        System.out.println(String.format("Consumer %d Waiting for messages. To exit press CTRL+C", this.no));
        // 4、监听并消费消息
        DeliverCallback deliverCallback = (consumerTag, delivery) -> {
            String message = new String(delivery.getBody(), "UTF-8");
            System.out.println(String.format("Consumer %d received message: %s", this.no, message));
            try {
                // 执行任务
                doWork(message);
            } finally {
                System.out.println(String.format("Consumer %d work done", this.no));
                // 手动ACK
                channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
            }
        };
        // 监听消息,关闭自动ACK
        channel.basicConsume(WORK_QUEUE, false, deliverCallback, consumerTag -> { });
    }

    /**
     * 执行任务
     * @param message
     */
    private void doWork(String message) {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}

几点说明:

  • channel.basicConsume(WORK_QUEUE, false, deliverCallback, consumerTag -> { });第二个参数设置为false,关闭自动ACK
  • DeliverCallback中,使用try...finally将代码包裹起来并在finally中手动进行ACK

1.4 运行

首先,启动2个消费者,消费者处于异步监听消息的状态。

然后,启动发送者,每隔2秒发送一条消息。

发送者运行结果如下:

D:\dev-env\java\jdk1.8.0_181\bin\java.exe ...
Send message: Simple Queue Message, count = 1
Send message: Simple Queue Message, count = 2
Send message: Simple Queue Message, count = 3
Send message: Simple Queue Message, count = 4
Send message: Simple Queue Message, count = 5
Send message: Simple Queue Message, count = 6

消费者运行结果如下:

D:\dev-env\java\jdk1.8.0_181\bin\java.exe ...
Consumer 2 Waiting for messages. To exit press CTRL+C
Consumer 1 Waiting for messages. To exit press CTRL+C
Consumer 1 received message: Simple Queue Message, count = 1
Consumer 1 work done
Consumer 2 received message: Simple Queue Message, count = 2
Consumer 2 work done
Consumer 1 received message: Simple Queue Message, count = 3
Consumer 1 work done
Consumer 2 received message: Simple Queue Message, count = 4
Consumer 2 work done
Consumer 1 received message: Simple Queue Message, count = 5
Consumer 1 work done
Consumer 2 received message: Simple Queue Message, count = 6
Consumer 2 work done

2 基于Spring AMQP代码示例

// TODO

你可能感兴趣的:(RabbitMQ)