rabbit-基础请求模式

基础请求模式简图:

服务A 发送消息给rabbit的队列,服务B监听这个队列,发现队列有消息了就获取消息。

代码:

1、maven依赖

<dependency>
            <groupId>com.rabbitmq</groupId>
            <artifactId>amqp-client</artifactId>
            <version>4.0.2</version>
        </dependency>

2、开发代码

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

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

/**
 * 工具类
 * Created by py
 * 2020/4/19
 */
public class RabbitUtils {

    public static Connection getInstance() throws IOException, TimeoutException {
        ConnectionFactory connectionFactory = new ConnectionFactory();
        connectionFactory.setHost("127.0.0.1");
        connectionFactory.setPort(5672);
        connectionFactory.setUsername("admin_py");
        connectionFactory.setPassword("123456");
        connectionFactory.setVirtualHost("/adminPy");
        Connection connection = connectionFactory.newConnection();
        return connection;
    }
}
import com.example.springcloud.eurekaclinet1demo.uitl.RabbitUtils;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;

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

/**
 * 消息生产者
 * Created by py
 * 2020/4/19
 */
public class SendRabbit {

    public static void main(String[] args) throws IOException, TimeoutException {
        /** 获取一个连接 */
        Connection instance = RabbitUtils.getInstance();
        /** 从连接中创建通道 */
        Channel channel = instance.createChannel();
        /** 在通道中声明一个队列
         * 因为我们要往队列里面发送消息,这是后就得知道往哪个队列中发送,就好比在哪个管子里面放水
         * */
        boolean durable=false;//数据是否持久化:即rabbit服务关闭了,rabbit中的信息是否会保存
        boolean exclusive=false;//信息只允许一个交换机处理,还是允许多个交换机处理
        boolean autoDelete=false;//队列中信息处理完是否自动删除该队列
        //simple_queue:队列名称
        channel.queueDeclare("simple_queue",durable,exclusive,autoDelete,null);
        String msg = "This is simple queque!";
        //将消息发送到队列simple_queue中
        channel.basicPublish("","simple_queue",null,msg.getBytes());
        channel.close();
        instance.close();
        System.out.println("信息发送成功");
    }




}
import com.example.springcloud.eurekaclinet1demo.uitl.RabbitUtils;
import com.rabbitmq.client.*;

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

/**
 * 消息消费者
 * Created by py
 * 2020/4/19
 */
public class RecRabbit {


    public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {
        Connection instance = RabbitUtils.getInstance();
        Channel channel = instance.createChannel();
        //声明队列 如果能确定是哪一个队列 这边可以删掉,不去掉 这里会忽略创建
        channel.queueDeclare("simple_queue",false,false,false,null);
        //定义消费者用来处理收到的消息
        DefaultConsumer defaultConsumer = new DefaultConsumer(channel){
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                super.handleDelivery(consumerTag, envelope, properties, body);
                //将消息转成字符串
                String message = new String(body, "UTF-8");
                System.err.println("new==Received '" + message + "'");
            }
        };
        //simple_queue:队列名称
        //true:自动确认;消费者直接告诉rabbit消息以处理,此时rabbit会将该条信息从simple_queue队列中删除
        //defaultConsumer:用于具体处理接受消息的方法
        channel.basicConsume("simple_queue",true,defaultConsumer);
    }
}

QA:当客户端请求量增大之后一台服务器难以支持大量的数据请求,那这个时候我们需要对服务进行集群操作,那rabbit如何将消息发给集群的服务呢?

/**
 * 生产者
 * 轮询策略 Round-robin 将消息平均的分发给每一个消费者
 * Created by py
 * 2020/4/19
 */
public class SendRabbit {

    public static void main(String[] args) throws IOException, TimeoutException {
        Connection instance = RabbitUtils.getInstance();
        Channel channel = instance.createChannel();
        channel.queueDeclare("work_queue",false,false,false,null);
        for (int i = 0; i < 50; i++) {
            String msg = "This is work queue!==="+i;
            channel.basicPublish("","work_queue",null,msg.getBytes());
        }
        channel.close();
        instance.close();
    }
}
/**
 * 消费者1
 * Created by py
 * 2020/4/19
 */
public class FristConsumer {

    public static void main(String[] args) throws IOException, TimeoutException {
        Connection instance = RabbitUtils.getInstance();
        Channel channel = instance.createChannel();
        channel.queueDeclare("work_queue",false,false,false,null);
        DefaultConsumer consumer = new DefaultConsumer(channel){
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                super.handleDelivery(consumerTag, envelope, properties, body);
                String str = new String(body,"utf-8");
                System.out.println("FristConsumer==="+str);
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };
        boolean autoAck = true; //消息的确认模式自动应答
        channel.basicConsume("work_queue",autoAck,consumer);
    }
}

import com.example.springcloud.eurekaclinet1demo.uitl.RabbitUtils;
import com.rabbitmq.client.*;

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

/**
 * 消费者2
 * Created by py
 * 2020/4/19
 */
public class SecondConsumer {

    public static void main(String[] args) throws IOException, TimeoutException {
        Connection instance = RabbitUtils.getInstance();
        Channel channel = instance.createChannel();
        channel.queueDeclare("work_queue",false,false,false,null);
        DefaultConsumer consumer = new DefaultConsumer(channel){
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                super.handleDelivery(consumerTag, envelope, properties, body);
                String str = new String(body,"utf-8");
                System.out.println("SecondConsumer==="+str);
                try {
                    Thread.sleep(2500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };
        boolean autoAck = true; //消息的确认模式自动应答
        channel.basicConsume("work_queue",autoAck,consumer);
    }
}

这样可以实现消息轮询的发送给两个服务器,但是有一个问题,SecondConsumer 执行一个请求sleep2.5S,FristConsumer 执行一个请求sleep0.5S,将请求平均的发送给两台服务器的话会导致FristConsumer 有很长的一段空闲时间,SecondConsumer的接收的那部分请求要很久才能完成。

QA:如何让生产端的数据尽可能快的执行完呢?

放弃轮询发送,根据消费端的消费情况来推送消息,即哪个服务器执行完成了就给他下一条消息,让FristConsumer 会多执行部分请求,SecondConsumer少执行部分请求,这样就能尽可能快的消费完生产者创建的消息了。

/**
 * 生产者
 * Fair dispatch(公平分发) 处理完当前信息在分发下一个信息
 * Created by py
 * 2020/4/19
 */
public class SendRabbit {
    final static String queue = "work_queue_durable";
    public static void main(String[] args) throws IOException, TimeoutException {
        Connection instance = RabbitUtils.getInstance();
        Channel channel = instance.createChannel();
        //设置rabbit信息持久化,为true时rabbit会将消息写入磁盘中
        boolean durable = true;
        //PS:rabbit不支持修改已声明的队列,
        //若一个队列声明的时候为设置持久化,声明后在设置持久化就会报错,
        //想要操作要么把队列删除重新声明该队列,要命声明一个新队列设置持久化
        channel.queueDeclare(queue,durable,false,false,null);

        int prefetchCount = 1;
        //每个消费者发送确认信号之前,消息队列不发送下一个消息过来,一次只处理一个消息
        //限制发给同一个消费者不得超过1条消息
        channel.basicQos(prefetchCount);
        // 发送的消息
        for (int i = 0; i < 50; i++) {
            String msg = "This is work queue!==="+i;
            channel.basicPublish("","work_queue",null,msg.getBytes());
        }
        channel.close();
        instance.close();
    }
}
/**
 * 消费者1
 * Created by py
 * 2020/4/19
 */
public class FristConsumer {
    final static String queue = "work_queue_durable";
    public static void main(String[] args) throws IOException, TimeoutException {
        Connection instance = RabbitUtils.getInstance();
        Channel channel = instance.createChannel();
        //设置rabbit信息持久化,为true时rabbit会将消息写入磁盘中
        boolean durable = true;
        //PS:rabbit不支持修改已声明的队列,
        //若一个队列声明的时候为设置持久化,声明后在设置持久化就会报错,
        //想要操作要么把队列删除重新声明该队列,要命声明一个新队列设置持久化
        channel.queueDeclare(queue,durable,false,false,null);
        //每个消费者发送确认信号之前,消息队列不发送下一个消息过来,一次只处理一个消息
        //限制发给同一个消费者不得超过1条消息
        channel.basicQos(1);

        DefaultConsumer consumer = new DefaultConsumer(channel){
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                super.handleDelivery(consumerTag, envelope, properties, body);
                String str = new String(body,"utf-8");
                System.out.println("FristConsumer==="+str);
                try {
                    Thread.sleep(1500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    //手动回复rabbit消息已处理
                    channel.basicAck(envelope.getDeliveryTag(),false);
                }
            }
        };
        //消息的确认模式:禁止自动应答
        boolean autoAck = false;
        channel.basicConsume("work_queue",autoAck,consumer);
    }
}
import com.example.springcloud.eurekaclinet1demo.uitl.RabbitUtils;
import com.rabbitmq.client.*;

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

/**
 * 消费者2
 * Created by py
 * 2020/4/19
 */
public class SecondConsumer {
    final static String queue = "work_queue_durable";
    public static void main(String[] args) throws IOException, TimeoutException {
        Connection instance = RabbitUtils.getInstance();
        Channel channel = instance.createChannel();
        //设置rabbit信息持久化,为true时rabbit会将消息写入磁盘中
        boolean durable = true;
        //PS:rabbit不支持修改已声明的队列,
        //若一个队列声明的时候为设置持久化,声明后在设置持久化就会报错,
        //想要操作要么把队列删除重新声明该队列,要命声明一个新队列设置持久化
        channel.queueDeclare(queue,durable,false,false,null);
        //每个消费者发送确认信号之前,消息队列不发送下一个消息过来,一次只处理一个消息
        //限制发给同一个消费者不得超过1条消息
        channel.basicQos(1);
        DefaultConsumer consumer = new DefaultConsumer(channel){
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                super.handleDelivery(consumerTag, envelope, properties, body);
                String str = new String(body,"utf-8");
                System.out.println("SecondConsumer==="+str);
                try {
                    Thread.sleep(2500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    //手动回复rabbit消息已处理
                    channel.basicAck(envelope.getDeliveryTag(),false);
                }
            }
        };
        //消息的确认模式:禁止自动应答
        boolean autoAck = false;
        channel.basicConsume("work_queue",autoAck,consumer);
    }
}

PS:此处添加了一些新的参数,以实现我们的需求

每次只发送一条数据,等对方告知数据完成消费在发送下一条数据
channel.basicQos(1);
//prefetchSize:数据的大小;不写是不限制数据大小
//prefetchCount:设置一次发送几条数据
//global:默认false
public void basicQos(int prefetchSize, int prefetchCount, boolean global)
//手动回复rabbit消息已处理
channel.basicAck(envelope.getDeliveryTag(),false);
//deliveryTag:当前这条消息的标识,
//multiple:true:多条消息,false:1条消息;正常设置为false
public void basicAck(long deliveryTag, boolean multiple);
//消息的确认模式:禁止自动回复rabbit,这里设置为false配合basicAck()一起使用
boolean autoAck = false;
channel.basicConsume("work_queue",autoAck,consumer);

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值