RabbitMQ学习

本文详细介绍了RabbitMQ中的消息确认机制,包括自动应答和手动应答的区别,并通过示例展示了手动应答如何确保消息在消费者处理完毕后才被删除。此外,还探讨了消费者消息分发的公平性和不公平衡策略,以及如何通过设置`basicQos`调整分发方式。最后,提到了发布确认机制,确保消息在RabbitMQ持久化后才向生产者确认。
摘要由CSDN通过智能技术生成

信息手动应答

在建立的生产者消费者案例中。

消费端

 public static void main(String[] args) throws  Exception{

        Channel Channel = getConn.getchannel();

        /**
         * 
         * meeage表示接收的消息
         */
        DeliverCallback DeliverCallback=(consumer,meeage)->{
            System.out.println(new String(meeage.getBody())+"已拿到");
            try {
                Thread.sleep(20000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            /**
             * meeage.getEnvelope().getDeliveryTag()  消息标记Tag
             * false表示不批量应答,只应答这一个消息
             */
            System.out.println(new String(meeage.getBody())+"确认完成");
            Channel.basicAck(meeage.getEnvelope().getDeliveryTag(),false);
        };
        CancelCallback CancelCallback=consumer->{
            System.out.println("消息消费被中断");
        };
        /**
         * 一:消息队列名称
         * 二:是否自动应答
         * true
         * 就是当生产者发送消息之后,RabbitMq就会将队列中的消息删除,不会管消费者是否已经处理完了消息
         * 弊端就是当生产者发送数据之后,如果在消费者没有处理完消息就宕机了,那这个消息就丢失了
         *
         * false
         * 就是当生产者发送消息之后,RabbitMq不会立刻将队列中的消息删除,而是等消费者发送ACk(表示确认已经处理完毕),才
         * 会将队列中的消息删除,假若在没有发送ACK时,消费者宕机了,则这条消息会重新入队,被其他消费者获取。保证了消息不会丢失
         *
         * 三:没有消费成功的反馈
         * 四:拿取消费的回调
         */
        boolean AutoACk=false;
        System.out.println( "C3等待消息");
        Channel.basicConsume(DL,AutoACk,DeliverCallback,CancelCallback);

    }

在 Channel.basicConsume设置中,我们将消息应答改为false(手动应答)只有发送了ACk之后,

RabbitMQ才会删除消息,否则会重新入队

这里我们消费者发送了2条消息

"C:\Program Files\Java\jdk-14.0.1\bin\java.exe" "-javaagent:D:\IntelliJ IDEA 2021.3.3\lib\idea_rt.jar=56306:D:\IntelliJ IDEA 2021.3.3\bin" -Dfile.encoding=UTF-8 -classpath E:\IDEA_Project\com.hwx.java\target\classes;C:\Users\lxkj\.m2\repository\com\rabbitmq\amqp-client\5.9.0\amqp-client-5.9.0.jar;C:\Users\lxkj\.m2\repository\org\slf4j\slf4j-api\1.7.30\slf4j-api-1.7.30.jar;C:\Users\lxkj\.m2\repository\commons-io\commons-io\2.8.0\commons-io-2.8.0.jar;C:\Users\lxkj\.m2\repository\log4j\log4j\1.2.17\log4j-1.2.17.jar;C:\Users\lxkj\.m2\repository\com\guicedee\services\sl4j\1.0.13.5\sl4j-1.0.13.5.jar;C:\Users\lxkj\.m2\repository\com\guicedee\services\log4j-core\1.0.13.5\log4j-core-1.0.13.5.jar RabbitMQ.provider
发送消息
hello hwx
hello已发送
发送消息
hwx已发送

消费者一

"C:\Program Files\Java\jdk-14.0.1\bin\java.exe" "-javaagent:D:\IntelliJ IDEA 2021.3.3\lib\idea_rt.jar=56312:D:\IntelliJ IDEA 2021.3.3\bin" -Dfile.encoding=UTF-8 -classpath E:\IDEA_Project\com.hwx.java\target\classes;C:\Users\lxkj\.m2\repository\com\rabbitmq\amqp-client\5.9.0\amqp-client-5.9.0.jar;C:\Users\lxkj\.m2\repository\org\slf4j\slf4j-api\1.7.30\slf4j-api-1.7.30.jar;C:\Users\lxkj\.m2\repository\commons-io\commons-io\2.8.0\commons-io-2.8.0.jar;C:\Users\lxkj\.m2\repository\log4j\log4j\1.2.17\log4j-1.2.17.jar;C:\Users\lxkj\.m2\repository\com\guicedee\services\sl4j\1.0.13.5\sl4j-1.0.13.5.jar;C:\Users\lxkj\.m2\repository\com\guicedee\services\log4j-core\1.0.13.5\log4j-core-1.0.13.5.jar RabbitMQ.consumer
C1等待消息
hello已拿到

进程已结束,退出代码130

消费者二

"C:\Program Files\Java\jdk-14.0.1\bin\java.exe" "-javaagent:D:\IntelliJ IDEA 2021.3.3\lib\idea_rt.jar=56318:D:\IntelliJ IDEA 2021.3.3\bin" -Dfile.encoding=UTF-8 -classpath E:\IDEA_Project\com.hwx.java\target\classes;C:\Users\lxkj\.m2\repository\com\rabbitmq\amqp-client\5.9.0\amqp-client-5.9.0.jar;C:\Users\lxkj\.m2\repository\org\slf4j\slf4j-api\1.7.30\slf4j-api-1.7.30.jar;C:\Users\lxkj\.m2\repository\commons-io\commons-io\2.8.0\commons-io-2.8.0.jar;C:\Users\lxkj\.m2\repository\log4j\log4j\1.2.17\log4j-1.2.17.jar;C:\Users\lxkj\.m2\repository\com\guicedee\services\sl4j\1.0.13.5\sl4j-1.0.13.5.jar;C:\Users\lxkj\.m2\repository\com\guicedee\services\log4j-core\1.0.13.5\log4j-core-1.0.13.5.jar RabbitMQ.consumer
C2等待消息
hwx已拿到
hwx确认完成
hello已拿到
hello确认完成

进程已结束,退出代码130

消费者C1拿到hello之后,在还没有处理完成,没有发送ACK时我们关闭程序,此时我们发现hello被

消费者C2拿到了,这说明在消费者没有发送ACK之前,RabbitMQ不会删除队列中的这个消息,没有处理完毕重新入队,被C2拿到。

不公平分发

在生产者发送消息之后,默认情况下,消费者采用轮询分发,每一个消费端轮流处理每一个消息,

但是在这种情况下,有些消费者可能处理速度很慢,有些很快,这样造成快的消费端浪费的资源,这里我们可以设置分发方式。

设置分发方式在消费端的信道设置

//      true表示自动应答,false表示手动应答
        boolean AutoACk=false;

//      1表示不公平分发(能者多劳) ,0表示轮询分发
        int  pp=1;
        Channel.basicQos(pp);
        System.out.println( "C3等待消息");
        Channel.basicConsume(DL,AutoACk,DeliverCallback,CancelCallback);

其中的 Channel.basicQos()方法就是设置分发方式,默认是0。

发布确认

刚刚说到,假若在信息设置为持久化发送之后,但是在RabbitMQ还没有持久化的间隙时间内,RabbitMQ发送宕机,那么信息就丢失了,所以需要发布确认,即当RabbitMQ确实已经持久化之后,向生产者发布一个信息确认。

开启方式在创建信道后,使用

Channel.confirmSelect();

进行发布确认。

异步发布确认

交换机

FANOUT(消息/订阅)模式

消费者1

package RabbitMQ.three;


import com.rabbitmq.client.CancelCallback;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.DeliverCallback;
import comp.getConn;

public class provider {
    public static final String  EX="logs";

    public static void main(String[] args) throws Exception{

        Channel getchannel = getConn.getchannel();


//     声明交换机
       getchannel.exchangeDeclare(EX,"fanout");

//       获取临时队列 ,消费者断开连接就删除了
        String queue = getchannel.queueDeclare().getQueue();

//        第一个队列,第二个交换机,第三个队列与交换机绑定的key
        getchannel.queueBind(queue,EX,"");

        DeliverCallback DeliverCallback=(one,two)->{
            System.out.println(new String(two.getBody(),"UTF-8"));
        };

        CancelCallback CancelCallback=consumer->{

        };

//        队列名,是否开启自动应答,
        getchannel.basicConsume(queue,true,DeliverCallback,CancelCallback);
    }
}

消费者2

package RabbitMQ.three;


import com.rabbitmq.client.CancelCallback;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.DeliverCallback;
import comp.getConn;

public class provider2 {
    public static final String  EX="logs";

    public static void main(String[] args) throws Exception{

        Channel getchannel = getConn.getchannel();


//     声明交换机   fanout  (消息/订阅模式)
       getchannel.exchangeDeclare(EX,"fanout");

//       获取临时队列 ,消费者断开连接就删除了
        String queue = getchannel.queueDeclare().getQueue();

//        第一个队列,第二个交换机,第三个队列与交换机绑定的key
        getchannel.queueBind(queue,EX,"");

        DeliverCallback DeliverCallback=(one,two)->{
            System.out.println(new String(two.getBody(),"UTF-8"));
        };

        CancelCallback CancelCallback=consumer->{

        };

//        队列名,是否开启自动应答,
        getchannel.basicConsume(queue,true,DeliverCallback,CancelCallback);
    }
}

生产者

package RabbitMQ.three;


import com.rabbitmq.client.Channel;
import comp.getConn;

import java.util.Scanner;

public class consumer {

    public static final String  JHJ="logs";

    public static void main(String[] args) throws Exception{

        Channel getchannel = getConn.getchannel();


        Scanner in=new Scanner(System.in);
        do{
            System.out.println("输入消息:");
            String  tx=in.next();
            getchannel.basicPublish(JHJ,"",null,tx.getBytes("UTF-8"));
        }while (in.hasNext());

    }
}

这里获取一个临时队列,绑定的key为字符空,这里的两个消费者代码是完全一样的,

生产者向队列绑定交换机的key发送消息,即"",因为消费者一和二绑定的都是"",所以两个人都可以收到。即实现了消息/订阅,即广播。

DIRECT 直接模式

直接模式中,即可以针对性的发送给某些消费端

消费者一

//      DIRECT为直连模式
        getchannel.exchangeDeclare(JHJ, BuiltinExchangeType.DIRECT);

//       设置队列
        getchannel.queueDeclare("ap_one",false,false,false,null);

//        绑定交换机,key值为info
        getchannel.queueBind("ap_one",JHJ,"info");
        getchannel.queueBind("ap_one",JHJ,"warn");

消费者二

//      DIRECT为直连模式
        getchannel.exchangeDeclare(JHJ, BuiltinExchangeType.DIRECT);

//       设置队列
        getchannel.queueDeclare("ap_two",false,false,false,null);

//        绑定交换机,key值为error
        getchannel.queueBind("ap_two",JHJ,"error");

生产者发送消息

getchannel.basicPublish(JHJ,"info",null,iix.getBytes(StandardCharsets.UTF_8));

这里的第一项是交换机名称,第二项是key,这里是向key为info发送消息,即消费者一才能收到,

当然,消费者一绑定了两个key,所以向warn发送也是消费者一才能收到,向eroor发送就只有

消费者二才能收到。

OTPIC 主题模式

主题模式主要就是设置key值改变了

key值的设置必须满足 单词.单词 ,这里的单词可以是小于255的任意字符,只有之间用 .  连接即可

消费者一

        getchannel.queueDeclare("one",false,false,false,null);

        getchannel.queueBind("one",HHH,"*.vip.*");

消费者二

getchannel.queueDeclare("one",false,false,false,null);

        getchannel.queueBind("one",HHH,"*.vip.vip");

消费者三

        getchannel.queueDeclare("two",false,false,false,null);

        getchannel.queueBind("two",HHH,"user.vip.*");

这里分别向

1. user.vip.ee  发送消息

2. er.vip.vip 发送消息

3. erer.common.pp 发送消息

其中,1被消费者三的two队列和one队列接收

2同时满足消费者一和消费者二,但是由于两个消费者是同一个队列,

所以只能有一个获取消息

3.不满足任何一个队列

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爷可是个天才

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值