Rabbit 使用笔记(2)-工作队列

这一节我们要讨论的场景是:首先我们开启了多个消费者,一个生产者。此时,我们的消费者如何接收消息。

我们对第 1 节的代码进行修改,这次我们生产者端发送多个消息

// 发送多个消息,每个消息的结尾带上数字标识,消费者端根据这个数字标识决定须要处理多少秒时间。

for (int i = 0; i < 10; i++) {
    String messages = "helloworld " + i;
    channel.basicPublish("", QUEUE_NAME, null, messages.getBytes());
}

消费者端:

    public class Receiver {

    private final static String QUEUE_NAME = "liwei";

    public static void main(String[] args) throws IOException, ShutdownSignalException, ConsumerCancelledException, InterruptedException {

        // 定义 rabbitmq 服务器的连接
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("192.168.199.121");
        Connection connection = factory.newConnection();

        // 声明要接收的消息队列(这一步和发送端还是一样的)
        Channel channel = connection.createChannel();
        channel.queueDeclare(QUEUE_NAME, false, false, false, null);

        // 定义消费者进行消费
        QueueingConsumer consumer = new QueueingConsumer(channel);
        // 如果第 2 个参数为 false ,消费者从一个 queue 中可以多次获取
        // 如果为 true ,表示消费者给了中间件一个应答,队列中的消息就不会再被消费了
        channel.basicConsume(QUEUE_NAME, true, consumer);

        while (true) {
            QueueingConsumer.Delivery delivery = consumer.nextDelivery();
            String message = new String(delivery.getBody());
            System.out.println("接收端收到:" + message);
            // 根据接收到得不同消息的尾数,决定处理多少时间
            dowork(message);

        }

    }

    // 这里假装很忙的样子
    private static void dowork(String message) throws InterruptedException {
        Integer num = Integer.valueOf(message.substring(message.length()-1));
        Thread.sleep(num*1000);
    }
}

然后我们先运行多个消费者,再运行一个生产者。我们会发现三个消费者的控制台是这样输出的:

接收端收到:helloworld 0
接收端收到:helloworld 3
接收端收到:helloworld 6
接收端收到:helloworld 9
接收端收到:helloworld 1
接收端收到:helloworld 4
接收端收到:helloworld 7
接收端收到:helloworld 2
接收端收到:helloworld 5
接收端收到:helloworld 8

结论:默认来说,RabbitMQ 会按顺序得把消息发送给每个消费者(Consumer)。平均每个消费者都会收到同等数量得消息。这种发送消息得方式叫做——轮询(round-robin)。

我们再做一个实验,同样开启三个消费者,一个发送者。然后再运行中 kill 掉 2 个消费者。可以看到它们接收的情况:

接收到 1 条消息以后就被 kill 的消费者:

接收端收到:helloworld 0

接收到 1 条消息以后就被 kill 的消费者:

接收端收到:helloworld 1

唯一正常留下来的消费者:

接收端收到:helloworld 2
接收端收到:helloworld 5
接收端收到:helloworld 8

我们可以得出结论:自动应答的情况下,消费者好像仍然在“接收消息”,但是并没有在处理消息。这种情况并不是我们想要看到的,因为有些消息没有得到正确的响应和处理。

下面我们介绍如何关闭自动应答,并给出回执。
第 1 步:在消费者声明接收的时候,取消自动应答:

boolean autoAck = false;
channel.basicConsume(QUEUE_NAME, autoAck, consumer);

第 2 步:在消费者接收消息以后,给一个回执给生产者

// 接收到消息以后,给一个回执            channel.basicAck(delivery.getEnvelope().getDeliveryTag(),false);

源代码:

/**
     * Acknowledge one or several received
     * messages. Supply the deliveryTag from the {@link com.rabbitmq.client.AMQP.Basic.GetOk}
     * or {@link com.rabbitmq.client.AMQP.Basic.Deliver} method
     * containing the received message being acknowledged.
     * @see com.rabbitmq.client.AMQP.Basic.Ack
     * @param deliveryTag the tag from the received {@link com.rabbitmq.client.AMQP.Basic.GetOk} or {@link com.rabbitmq.client.AMQP.Basic.Deliver}
     * @param multiple true to acknowledge all messages up to and
     * including the supplied delivery tag; false to acknowledge just
     * the supplied delivery tag.
     * @throws java.io.IOException if an error is encountered
     */
    void basicAck(long deliveryTag, boolean multiple) throws IOException;

这时,我们再做同样的测试:

被 kill 掉的消费者,原来 9 这条任务应该由这个消费者处理的,因为被 kill 掉,所以消息中间件没有收到 9 这个任务的回执信息,因此消息中间件又发给了下一个消费者来处理。

接收端收到:helloworld 0
接收端收到:helloworld 3
接收端收到:helloworld 6
接收端收到:helloworld 1
接收端收到:helloworld 5
接收端收到:helloworld 7
接收端收到:helloworld 9
接收端收到:helloworld 2
接收端收到:helloworld 4
接收端收到:helloworld 8
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值