rabbitmq循环发送

文章中的例子是来自于rabbitmq的官网,所以大家可以去官网上看一看。

这里讲一下循环发送的情况。概念图如下所示:

rabbitmq循环发送_第1张图片

在这里,我们会模拟一个耗时的任务在消费者中,通过Thread.sleep(1000)这个函数,模拟耗时任务。同时启动多个consumer。
其实可以说是rabbitmq本身就支持这种模式。

Producer代码

package com.bobo.rabbitmq2;

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

import java.io.IOException;
import java.nio.charset.Charset;
import java.util.concurrent.TimeoutException;

/**
 * 消息队列生产者,这个例子只是简单的通过queue使用,
 * 所以是exchange是“”
 * @author [email protected]
 * @create 2018-11-04 13:36
 **/
public class Send {

    public static void main(String[] args) throws IOException, TimeoutException {
        ConnectionFactory connectionFactory = new ConnectionFactory();
        connectionFactory.setHost("localhost");
        Connection connection = connectionFactory.newConnection();
        Channel channel = connection.createChannel();
        channel.queueDeclare("hello",false,false,false,null);
        String message = "hello world";
        for (int i =0 ;i <10;i++) {
            channel.basicPublish("","hello",null,(message+i).getBytes(Charset.forName("UTF-8")));
        }
        System.out.println(" [x] Sent '" + message + "'");
        //关闭连接
        channel.close();
        connection.close();
    }
}

这里用来发送消息是带一个i,用来在消费者区分。

comsumer代码

package com.bobo.rabbitmq2;

import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.Consumer;
import com.rabbitmq.client.DefaultConsumer;
import com.rabbitmq.client.Envelope;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

/**
 * 消息接收者
 * @author [email protected]
 * @create 2018-11-04 13:46
 **/
public class Receiver {

    public static void main(String[] args) throws IOException, TimeoutException {
        ConnectionFactory connectionFactory = new ConnectionFactory();
        connectionFactory.setHost("localhost");
        Connection connection = connectionFactory.newConnection();
        Channel channel = connection.createChannel();
        channel.queueDeclare("hello", false, false, false, null);
        System.out.println(" [*] Waiting for messages. To exit press CTRL+C");
        //回调消费消息
        Consumer consumer = new DefaultConsumer(channel) {
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body)
                    throws IOException {
                String message = new String(body, "UTF-8");
                System.out.println(" [x] Received '" + message + "'");
                try {
                    doWork(message);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    System.out.println(" [x] Done");
                }
            }
        };
        channel.basicConsume("hello", true, consumer);
    }

    private static void doWork(String task) throws InterruptedException {
        for (char ch: task.toCharArray()) {

            if (ch == '.') {
                Thread.sleep(1000);
            }
        }
    }
}

在消费者消费的时候,让线程睡一秒,来模拟耗时操作。

rabbitmq循环发送_第2张图片
rabbitmq循环发送_第3张图片

我们可以看到rabbitmq自动做了类似于负载均衡的操作,而且默认使用的轮询算法。所以当一个comsumer处理不过来的时候就可以多添加
几个comsumer。

消息确认

为了确保消息永远不会丢失,RabbitMQ支持消息确认。消费者将会发送一个确认信息来告诉RabbitMQ,我已经接收到了消息,并且处理完了
,你可以随便删它了。
如果一个消费者在发送确认信息前丢失(连接或通道关闭、TCP连接丢失等),RabbitMQ将会认为该消息没有被完全处理并会重新将消息加入队列。如果此时有其他的消费者,RabbitMQ很快就会重新发送该消息到其他的消费者。通过这种方式,你完全可以保证没有消息丢失,即使某个消费者意外死亡。
 channel.basicConsume("hello", true, consumer);
这个方法中的第二个参数就是消息确认机制,当为true的时候表示是有消息确认。

消息持久化

如果关闭RabbitMQ服务或者RabbitMQ服务崩溃了,RabbitMQ就会丢掉所有的队列和消息:除非你告诉它不要这样。要确保RabbitMQ服务
关闭或崩溃后消息不会丢失,要做两件事情:持久化队列、持久化消息。

首先,我们要确保RabbitMQ永远不会丢失我们的队列。怎么做呢?在声明队列的时候,指定durable参数为true。
channel.queueDeclare("hello",true,false,false,null);
queueDeclare的时候,当第二个参数是true,表示的是对列持久化。
 // MessageProperties.PERSISTENT_TEXT_PLAIN定义消息持久化
 channel.basicPublish("","hello",MessageProperties.PERSISTENT_TEXT_PLAIN,(message+i).getBytes(Charset.forName("UTF-8")));
将消息标记为持久化并不能完全保证消息不会丢失。尽管它告诉RabbitMQ将消息保存到磁盘中,但是在RabbitMQ接收到消息和
保存消息之间会与一个很短的时间窗。同时,RabbitMQ不会为每个消息做fsync(2)处理,消息可能仅仅保存到缓存中而不会真正
地写入到磁盘中。这种持久化保证尽管不够健壮,但已经远远足够我们的简单任务队列

公平分发

当有多个消费者的时候,rabbitmq主要是通过循环发送(也就是轮询)的方式发送的。
为了改变这种情况,我们可以使用basicQos方法,并将参数prefetchCount设为1。这样做,工作者就会告诉RabbitMQ:不要同
时发送多个消息给我,每次只发1个,当我处理完这个消息并给你确认信息后,你再发给我下一个消息。这时候,RabbitMQ就不
会轮流平均发送消息了,而是寻找闲着的工作者。

你可能感兴趣的:(rabbitmq)