RabbitMQ中的WorkQueues模型

Work Queues模型

img

这种模型有一个生产者,两个消费者,一个队列。

生产者向"hello"队列发送消息。消费者从该队列接收消息。

循环调度

默认情况下,RabbitMQ 会按顺序将每条消息发送给下一个使用者。平均而言,每个使用者都会收到相同数量的消息。这种分发消息的方式称为循环调度。

SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
=====2hello rabbitmq
=====4hello rabbitmq
=====6hello rabbitmq
=====8hello rabbitmq
=====10hello rabbitmq
=====12hello rabbitmq
=====14hello rabbitmq
=====16hello rabbitmq
=====18hello rabbitmq
=====20hello rabbitmq
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
=====1hello rabbitmq
=====3hello rabbitmq
=====5hello rabbitmq
=====7hello rabbitmq
=====9hello rabbitmq
=====11hello rabbitmq
=====13hello rabbitmq
=====15hello rabbitmq
=====17hello rabbitmq
=====19hello rabbitmq

消息确认机制

Problem:但是完成一项任务往往需要一段时间,如果一个消费者在执行任务期间宕机了,那么未被处理的消息就会全部丢失。

Solution:为了确保每一个消息都能被确认没有丢失,RabbitMQ就采用了消息确认的方式。只有当消费者返回给了RabbitMQ一个特定的消息告诉它这个消息已经从队列中正确接收,那么这条消息才会从队列中被移除。如果一个消费者宕机了(其通道关闭、连接关闭或 TCP 连接丢失)那么RabbitMQ 会知道消息没有完全处理,并将重新返回进队列。如果同时有其他在线消费者,它会迅速重新递送给其他消费者。这样,您就可以确保不会丢失任何消息,即使消费者偶尔会死亡。

1.开发消费者1(Accept1):

public static void main(String[] args) throws IOException, TimeoutException {
    Connection connection = RabbitMQUtils.getConnection("192.168.1.18", "/ems", 5672, "ems", "123");
    Channel channel = connection.createChannel();
    channel.basicConsume("hello", false, new DefaultConsumer(channel) {
        @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("=====" + new String(body));
        }
    });

    //channel.close();
    //connection.close();
}

2.开发消费者2(Accept2):

public static void main(String[] args) throws IOException, TimeoutException {
    Connection connection = RabbitMQUtils.getConnection("192.168.1.18", "/ems", 5672, "ems", "123");
    Channel channel = connection.createChannel();
    channel.basicConsume("hello", false, new DefaultConsumer(channel) {
        @Override
        public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
            System.out.println("=====" + new String(body));
            channel.basicAck(envelope.getDeliveryTag(),false); //消费者返回给了RabbitMQ一个特定的消息告诉它这个消息已经从队列中正确接收
        }
    });

    //channel.close();
    //connection.close();
}

在这里插入图片描述

由于Accept1种没有加channel.basicAck(envelope.getDeliveryTag(),false);从而导致处理的十条消息没有被确认。当其断开连接的时候Accept2会帮忙处理Accept1处理但未被确认的消息。

3.测试结果:

在这里插入图片描述

公平派送(能者多得,弱者少得)

Problem:但是上面这些还不是我们想要的结果。举个例子,比如当任务繁重的时候,会出现一个消费者工作而另一个消费者完全空闲。这是因为 RabbitMQ 只是在消息进入队列时调度一条消息,它不查看使用者未确认的消息数。它只是盲目地将每条 n 消息都调度到 n - th 使用者。‎

Solution:为了解决这个问题,我们就要用到,*channel.basicQos(1);*去声明每次消息队列只分发给消费者一个消息,只有你返回给我确认了我才会给你发下一条消息。

1.开发消费者1(Accept1):

public static void main(String[] args) throws IOException, TimeoutException {
    Connection connection = RabbitMQUtils.getConnection("192.168.1.18", "/ems", 5672, "ems", "123");
    Channel channel = connection.createChannel();
    channel.basicQos(1);
    channel.queueDeclare("hello", false, false, false, null);
    channel.basicConsume("hello", false, new DefaultConsumer(channel) {
        @Override
        public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
            System.out.println("=====" + new String(body));
            channel.basicAck(envelope.getDeliveryTag(),false);
        }
    });
    //channel.close();
    //connection.close();
}

2.开发消费者2(Accept2):

public static void main(String[] args) throws IOException, TimeoutException {
    Connection connection = RabbitMQUtils.getConnection("192.168.1.18", "/ems", 5672, "ems", "123");
    Channel channel = connection.createChannel();
    channel.basicQos(1);
    channel.queueDeclare("hello", false, false, false, null);
    channel.basicConsume("hello", false, new DefaultConsumer(channel) {
        @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("=====" + new String(body));
            channel.basicAck(envelope.getDeliveryTag(),false);
        }
    });
    //channel.close();
    //connection.close();
}

由于Accept2中在回调方法执行的时候线程休眠了2000毫秒,导致返回确认消息延时,使得Accept1将所有的消息都已接受。形成了能者多得,弱者少得的现象。

3.测试结果:

在这里插入图片描述
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值