初始RabbitMq(2)7个案例前两个

初识RabbitMq(2)7个案例前两个

Hello World(简单队列)

生产者------》消息队列-------》消费者

生产者

package org.example.simple.send;

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

import java.nio.charset.StandardCharsets;
/*
* 生产者
* */
public class Send {
    //队列名称
    private final static String QUEUE_NAME = "hello";

    public static void main(String[] argv) throws Exception {
        //创建连接工厂 port默认不用配置
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("xx.xx.xxx.xxx");
        factory.setUsername("****");
        factory.setPassword("***");
        factory.setVirtualHost("***");
        //try cache新写法
        try (
                //用连接工厂 创建连接 Connection继承了Closeable接口可以自动关闭
                Connection connection = factory.newConnection();
                //创建信道
                Channel channel = connection.createChannel()) {
                /*
                * 绑定队列 队列名
                * 持久化
                * 排他队列(基于连接课件,仅对首次声明它的连接可见,名字不能相同,连接关闭之后排他队列自动删除不管持久化)
                * 自动删除
                * 参数
                * */
                channel.queueDeclare(QUEUE_NAME, false, false, false, null);
                //message内容
                String message = "Hello World!";
                //发送消息 交换机
                channel.basicPublish("", QUEUE_NAME, null, message.getBytes(StandardCharsets.UTF_8));
                System.out.println(" [x] Sent '" + message + "'");
        }
    }
}

消费者

package org.example.simple.recv;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.DeliverCallback;
/*
* 消费者
* */
public class Recv {

    private final static String QUEUE_NAME = "hello";

    public static void main(String[] argv) throws Exception {
        //创建连接工厂 port默认不用配置
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("xx.xx.xxx.xxx");
        factory.setUsername("****");
        factory.setPassword("***");
        factory.setVirtualHost("***");
        //用连接工厂 创建连接 Connection继承了Closeable接口可以自动关闭
        Connection connection = factory.newConnection();
        //创建信道
        Channel channel = connection.createChannel();
        //绑定队列
        channel.queueDeclare(QUEUE_NAME, false, false, false, null);
        System.out.println(" [*] Waiting for messages. To exit press CTRL+C");

        DeliverCallback deliverCallback = (consumerTag, delivery) -> {
            //拿到消息
            String message = new String(delivery.getBody(), "UTF-8");
            System.out.println(" [x] Received '" + message + "'");
        };
        //监听队列 消费消息
        channel.basicConsume(QUEUE_NAME, true, deliverCallback, consumerTag -> { });
    }
}

优缺点

优点:简单

缺点:有可能消息堆积!消息供大于求,久而久之,造成内存或磁盘溢出。

解决方法增加消费者!!!

工作队列

工作队列概念(操作系统中):工作队列 ( workqueue )`是将操作(或回调)延期异步执行的一种机制。工作队列可以把工作推后,交由一个内核线程去执行,并且工作队列是执行在线程上下文中,因此工作执行过程中可以被重新调度、抢占、睡眠。

在RabbitMq中:

工作队列(又称任务队列)的主要思想是避免立即执行资源密集型任务,而不得不等待它完成。相反,我们安排任务在以后完成。我们将任务封装 为消息并将其发送到队列。在后台运行的工作进程 将弹出任务并最终执行作业。当您运行许多工作进程时,任务将在他们之间共享。

用来将耗时的任务分发给多个消费者(工作者),主要解决这样的问题:处理资源密集型任务,并且还要等他完成。有了工作队列,我们就可以将具体的工作放到后面去做,将工作封装为一个消息,发送到队列中,一个工作进程就可以取出消息并完成工作。如果启动了多个工作进程,那么工作就可以在多个进程间共享。

多个消费者一起工作,消费者处理消息的过程中其他消费者也在处理,减少休息时间,就加快了消费速度,达到提高消费能力的目的。

轮询模式

轮询——也可以说是循环,多个消费者一起工作,消费者处理消息的过程中其他消费者也在处理,减少休息时间,就加快了消费速度,达到提高消费能力的目的。

RabbitMQ 将按顺序将每条消息发送给下一个消费者,平均而言,每个消费者将获得相同数量的消息,这种分发消息的方式称为轮询。

就是多了消费者,A消费1号message,同时可以B消费2号message,如果A处理完了1号就可以消费3号message,但是如果B比A快,B不能接3号B接的是4号。

生产者
/*
* 工作队列-轮询-生产者
* */
public class Send {
    //队列名称
    private final static String QUEUE_NAME = "work_rr";

    public static void main(String[] argv) throws Exception {
        //创建连接工厂 port默认不用配置
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("*");
        factory.setUsername("*");
        factory.setPassword("*");
        factory.setVirtualHost("*");
        //try cache新写法
        try (
                //用连接工厂 创建连接 Connection继承了Closeable接口可以自动关闭
                Connection connection = factory.newConnection();
                //创建信道
                Channel channel = connection.createChannel()) {
                /*
                * 绑定队列 队列名
                * 持久化
                * 排他队列(基于连接课件,仅对首次声明它的连接可见,名字不能相同,连接关闭之后排他队列自动删除不管持久化)
                * 自动删除
                * 参数
                * */
                channel.queueDeclare(QUEUE_NAME, false, false, false, null);
                //发多条消息
                for(int i=0;i<20;i++){
                    //message内容
                    String message = "Hello World!Work"+i;
                    //发送消息 交换机
                    channel.basicPublish("", QUEUE_NAME, null, message.getBytes(StandardCharsets.UTF_8));
                    System.out.println(" [x] Sent '" + message + "'"+i);
                }
        }
    }
}
消费者
/*
* 工作队列-轮询 消费者1
* */
public class Recv {

    private final static String QUEUE_NAME = "work_rr";

    public static void main(String[] argv) throws Exception {
        //创建连接工厂 port默认不用配置
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("**********");
        factory.setUsername("***");
        factory.setPassword("*");
        factory.setVirtualHost("*");
        //用连接工厂 创建连接 Connection继承了Closeable接口可以自动关闭
        Connection connection = factory.newConnection();
        //创建信道
        Channel channel = connection.createChannel();
        //绑定队列
        channel.queueDeclare(QUEUE_NAME, false, false, false, null);
        System.out.println(" [*] Waiting for messages. To exit press CTRL+C");

        DeliverCallback deliverCallback = (consumerTag, delivery) -> {
            //拿到消息
            String message = new String(delivery.getBody(), "UTF-8");
            System.out.println(" [x] Received '" + message + "'");
            //手动确认 参数:multiple是否确认多条-》false逐条确认
            channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
        };
        //监听队列 消费消息
        //队列名称 自动回执
        channel.basicConsume(QUEUE_NAME, false, deliverCallback, consumerTag -> { });
    }
}

/*
* 工作队列-轮询 消费者2
* */
public class Recv2 {

    private final static String QUEUE_NAME = "work_rr";

    public static void main(String[] argv) throws Exception {
        //创建连接工厂 port默认不用配置
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("47.94.232.61");
        factory.setUsername("liu");
        factory.setPassword("liujiaxiang55");
        factory.setVirtualHost("/liu");
        //用连接工厂 创建连接 Connection继承了Closeable接口可以自动关闭
        Connection connection = factory.newConnection();
        //创建信道
        Channel channel = connection.createChannel();
        //绑定队列
        channel.queueDeclare(QUEUE_NAME, false, false, false, null);
        System.out.println(" [*] Waiting for messages. To exit press CTRL+C");

        DeliverCallback deliverCallback = (consumerTag, delivery) -> {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //拿到消息
            String message = new String(delivery.getBody(), "UTF-8");
            System.out.println(" [x] Received '" + message + "'");
            //手动确认 参数:multiple是否确认多条-》false逐条确认
            channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
        };
        //监听队列 消费消息
        //队列名称 自动回执
        channel.basicConsume(QUEUE_NAME, false, deliverCallback, consumerTag -> { });
    }
}
优缺点

优点:解决生产者生产能力大于消费的消费能力,减少多余消息堆积。

缺点:水桶效应,工作快的要等工作慢的。上面提到的但是如果B比A快,B不能接3号B接的是4号,队列最终消费完是算消费最慢的时间。

假如有一些非常耗时的任务,某个消费者在缓慢地进行处理,而另一个消费者则空闲,队列不能关闭,显然是非常消耗资源的。

公平模式

能者多劳!

如果B比A快,B能接3号不必等A接3号,没有停歇!谁有空谁就接着干!

做到能者多劳,没有资源浪费。

关键代码:

//在创建信道后 限制消费者每次只能接收一(prefetchCount)条消息,处理完才能接收下一条
        int prefetchCount = 1;
        channel.basicQos(prefetchCount);

参考

工作队列

RabbitMq官网

RabbitMQ入门:工作队列(Work Queue

b站视频教程(不知道是不是正版,侵删)

感谢!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值