RabbitMQ(15672) 消息中间件 NOTE

目录

1、初识 RabbitMQ 消息队列

1.1 MQ 四大核心概念

1.2 消息的发送(无交换机态)

1.3 关于消息自动重新入队

1.3.1 消息的常见应答方法(R)

1.4 关于 RabbitMQ 的持久化、不公平分发以及预取值

2、RabbitMQ 消息的发布确认

2.1 MQ的单个确认发布

2.2 MQ的批量确认发布

2.3 MQ的异步确认发布(重点)

3、关于 Exchanges 交换机

4、死信队列(重点)

5、延迟队列(整合SpringBoot)

6、备份交换机(重点)


 什么是 RabbitMQ ?

        RabbitMQ 是流行的消息队列服务软件,是开源的AMQP(高级消息队列协议)实现;支持多种客户端,如:Java、Python、C、PHP、Ruby、JavaScript等,用于在分布式系统中存储转发消息,可以实现异步处理、流量削峰、系统解耦,在易用性、扩展性、高可用等方面表现优异

1、初识 RabbitMQ 消息队列

1.1 MQ 四大核心概念

生产者:

产生数据发送消息的程序

交换机:

交换机是 RabbitMQ 非常重要的一个部件,一方面它接收来自生产者的消息,另一方面它将消息推送到队列中;交换机必须确切知道如何处理它接收到的消息,是将这些消息推送到特定队列还是推送到多个队列,亦或者是把消息丢弃,这个得有交换机类型决定

队列:

队列是 RabbitMQ 内部使用的一种数据结构,尽管消息流经 RabbitMQ 和应用程序,但它们只能存储在队列中;队列仅受主机的内存和磁盘限制的约束,本质上是一个大的消息缓冲区;许多生产者可以将消息发送到一个队列,许多消费者可以尝试从一个队列接收数据;这就是我们使用队列的方式

消费者:

消费与接收具有相似的含义;消费者大多时候是一个等待接收消息的程序;生产者,消费者和消息中间件很多时候并不在同一机器上;同一个应用程序既可以是生产者又是可以是消费者

以下是 RabbitMQ 的原理图:

1.2 消息的发送(无交换机态)

这里使用MQ中间件进行简单的消息发送,大致流程图如下所示:

这里需要注意的是,当一次性有多条消息发送到队列时,这时需要多个消费者(工作线程),消费者进行消费信息是根据轮询的方式进行消费

创建一个Utils工具类,与 MQ 进行交互连接:

/**
 * 这里是与 MQ 交互的工具类
 */
public class RabbitMQUtils {

    public static Channel getChannel() throws IOException, TimeoutException {

        ConnectionFactory factory = new ConnectionFactory();    //创建连接工厂

        factory.setHost("192.168.101.65");
        factory.setUsername("admin");
        factory.setPassword("123");

        Connection connection = factory.newConnection();    //创建连接

        return connection.createChannel();  //获取连接信道
    }
}

【消息生产者】代码如下所示:

/**
 * 生产者
 */
public class Produce {

    public static final String QUEUE_NAME = "hello";    //队列名称

    public static void main(String[] args) throws IOException, TimeoutException {

        //这里创建一个工厂,与 RabbitMQ 进行交互
        Channel channel01 = RabbitMQUtils.getChannel();

        //1.队列名称  2.队列是否持久化  3.消息是否供多个消费者消费  4.消息是否自动删除  5.其他参数
        channel01.queueDeclare(QUEUE_NAME,false,false,false,null);


        String message = "hello mq";    //发消息

        //1.对应的交换机  2.路由的KEY值(本次是队列名)   3.其他参数  4.发送消息的消息体
        channel01.basicPublish("",QUEUE_NAME,null,message.getBytes());

        System.out.println("消息发送完毕!");

    }
}

消息栏:

RabbitMQ 中(以上创建的 hello 队列):

【消息消费者】代码如下所示:

/**
 * 消费者
 */
public class Consumer {

    public static final String QUEUE_NAME = "hello";    //要进行消费消息的队列

    public static void main(String[] args) throws IOException, TimeoutException {

        //创建连接工厂,与MQ进行交互
        Channel channel = RabbitMQUtils.getChannel();

        //接收消息的回调
        DeliverCallback deliverCallback = (consumerTag,message)->{

            System.out.println("成功接收消息:"+new String(message.getBody()));    //接收其消息的消息体才能显示对应的消息
        };
        
        //取消消息时的回调
        CancelCallback cancelCallback = (consumerTag) ->{

            System.out.println(consumerTag + "消费者的消息被中断!");
        };
        
        /**
         * 1.要被消费信息的队列
         * 2.消费成功之后是否需要自动应答
         * 3.消费成功时的回调
         * 4.取消消息发送时的回调
         */
        //消费者消费信息
        channel.basicConsume(QUEUE_NAME,true,deliverCallback,cancelCallback);
    }
}

消息栏:

MQ 中的消息已经被消费:


1.3 关于消息自动重新入队

        如果消费者由于某些原因失去连接(其通道已关闭,连接已关闭或 TCP 连接丢失),导致消息 未发送 ACK 确认,RabbitMQ 将了解到消息未完全处理,并将对其重新排队;如果此时其他消费者可以处理,它将很快将其重新分发给另一个消费者;这样,即使某个消费者偶尔死亡,也可以确 保不会丢失任何消息

1.3.1 消息的常见应答方法(R)

  • Channel.basicAck (用于肯定确认) RabbitMQ 已知道该消息并且成功的处理消息,可以将其丢弃了

  • Channel.basicNack (用于否定确认)

  • Channel.basicReject (用于否定确认) 与 Channel.basicNack 相比少一个参数

        不处理该消息了直接拒绝,可以将其丢弃了

丢失的消息重新入队,传递给正常工作的消费者进行消费的大致图:

由于生产者的代码没有改变,这里就不写了,以下是消费者(两个消费者只有 sleep 的时间不一样)关于 ACK 手动应答消息的代码:

/**
 * 这里是消费者手动接受消息 ACK,使发送失败的消息重新排队
 */
public class Consumer01 {

    public static final String QUEUE_NAME = "ack_queue";

    public static void main(String[] args) throws IOException, TimeoutException {

        Channel channel = RabbitMQUtils.getChannel();

        SleepUtils.sleep(8);   //模拟消息多的情况

        //1、接收到消息的回调
        DeliverCallback deliverCallback = (consumerTag,message) ->{

            System.out.println("接收到消息:" + new String(message.getBody(), StandardCharsets.UTF_8));

            /**
             * 手动应答
             * 1. 消息的标记
             * 2. 是否批量应答信道中的消息
             */
            channel.basicAck(message.getEnvelope().getDeliveryTag(), false);
        };

        //2.消息中断的回调
        CancelCallback  cancelCallback = (consumerTag) -> {

            System.out.println(consumerTag + "消费者取消了消息的接收!");
        };

        //3.使用手动应答
        boolean autoACK = false;
        channel.basicConsume(QUEUE_NAME,autoACK,deliverCallback,cancelCallback);
    }
}

首先创建两个消费者,分别为C1和C2,这里生产者连续发送四条消息: 

消费者一 处于正常状态消费者二 接收了一条消息后就宕机了,这时,消费者一 将发送失败的消息从信道中取出并进行消费,结果图如下所示:

消费者一:         消费者二:

可见, 就算消费者二突然宕机,RabbitMQ 依然采用轮询方式将发送失败的消息轮询给正常工作的消费者

1.4 关于 RabbitMQ 的持久化、不公平分发以及预取值

队列的持久化:

平时消息队列都是保存在内存中,若 RabbitMQ服务 突然停止,则之前的队列都会消失;所以,为了减少损失的可能性,通常将消息队列保存到磁盘上,即持久化

boolean durable =true;  //将队列进行持久化
        //1.队列名称  2.队列是否持久化  3.消息是否供多个消费者消费  4.消息是否自动删除  5.其他参数
        channel01.queueDeclare(QUEUE_NAME,durable,false,false,null);


 

消息的持久化:

将 MessageProperties.PERSISTENT_TEXT_PLAIN 标识放入 basicPublish消息发送方法的第三个参数中,以开启消息持久化

将消息标记为持久化并不能完全保证不会丢失消息;尽管它告诉 RabbitMQ 将消息保存到磁盘,但是,这里依然存在当消息刚准备存储在磁盘的时候,还没有存储完,消息还在缓存的一个间隔点;此时并没有真正写入磁盘

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

迷迷的k

感谢长的这么帅还来打赏我

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

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

打赏作者

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

抵扣说明:

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

余额充值