消息队列RabbitMQ

1.RabbitMQ的使用场景

1.任务异步处理
将不需要同步处理的并且耗时长的操作由消息队列通知消息接收方进行异步处理。提高了应用程序的响应时间。
2.应用程序解耦合
MQ相当于一个中介,生产方通过MQ与消费方交互,它将应用程序进行解耦合。
2.削峰填谷
- 如订单系统,在下单的时候就会往数据库写数据。但是数据库只能支撑每秒1000左右的并发写入,并发量再高就容易宕机。低峰期的时候并发也就100多个,但是在高峰期时候,并发量会突然激增到5000以上,这个时候数据库肯定卡死了。
在这里插入图片描述
消息被MQ保存起来了,然后系统就可以按照自己的消费能力来消费,比如每秒1000个数据,这样慢慢写入数据库,这样就不会卡死数据库了。
在这里插入图片描述
但是使用了MQ之后,限制消费消息的速度为1000,但是这样一来,高峰期产生的数据势必会被积压在MQ中,高峰就被“削”掉了。但是因为消息积压,在高峰期过后的一段时间内,消费消息的速度还是会维持在1000QPS,直到消费完积压的消息,这就叫做“填谷”
在这里插入图片描述

2.实现MQ的主流方式?以及区别

MQ是消息通信的模型;实现MQ的大致有两种主流方式:AMQP、JMS。
AMQP是一种协议,更准确的说是一种binary wire-level protocol(链接协议)。这是其和JMS的本质差别,AMQP不从API层进行限定,而是直接定义网络交换的数据格式。
JMS即Java消息服务(JavaMessage Service)应用程序接口,是一个Java平台中关于面向消息中间件(MOM)的API,用于在两个应用程序之间,或分布式系统中发送消息,进行异步通信。
AMQP 与 JMS 区别

  • JMS是定义了统一的接口,来对消息操作进行统一;AMQP是通过规定协议来统一数据交互的格式
  • JMS限定了必须使用Java语言;AMQP只是协议,不规定实现方式,因此是跨语言的。
  • JMS规定了两种消息模式;而AMQP的消息模式更加丰富

3.rabbitmq基于什么实现的?什么语言开发的?

RabbitMQ:基于AMQP协议,erlang语言开发,稳定性好

4.rabbitmq消息模式?

RabbitMQ提供了6种模式:简单模式,work模式,Publish/Subscribe发布与订阅模式,Routing路由模式,Topics主题模式,RPC远程调用模式(远程调用,不太算MQ;暂不作介绍)
在这里插入图片描述

5.rabbitmq的组成

RabbitMQ的核心组成部分

在这里插入图片描述
核心概念:
Server:又称Broker ,接受客户端的连接,实现AMQP实体服务。 安装rabbitmq-server
Connection:连接,应用程序与Broker的网络连接 TCP/IP/ 三次握手和四次挥手

Channel:网络信道,几乎所有的操作都在Channel中进行,Channel是进行消息读写的通道,客户端可以建立对各Channel,每个Channel代表一个会话任务。

Message :消息:服务与应用程序之间传送的数据,由Properties和body组成,Properties可是对消息进行修饰,比如消息的优先级,延迟等高级特性,Body则就是消息体的内容。

Virtual Host: 虚拟地址,用于进行逻辑隔离,最上层的消息路由,一个虚拟主机理由可以有若干个Exhange和Queueu,同一个虚拟主机里面不能有相同名字的Exchange

Exchange:交换机,接受消息,根据路由键发送消息到绑定的队列。(不具备消息存储的能力)

Bindings:Exchange和Queue之间的虚拟连接,binding中可以保护多个routing key.

Routing key:是一个路由规则,虚拟机可以用它来确定如何路由一个特定消息。

Queue:队列:也成为Message Queue,消息队列,保存消息并将它们转发给消费者。

交换机(Exchange)类型

RabbitMQ 支持多种交换机(Exchange)类型,每种类型都用于不同的消息路由和分发策略:

1、Direct Exchange:

这种交换机根据消息的路由键(Routing Key)将消息发送到与之完全匹配的队列。只有当消息的路由键与队列绑定时指定的路由键完全相同时,消息才会被路由到队列。这是一种简单的路由策略,适用于点对点通信。

2、Topic Exchange:

这种交换机根据消息的路由键与队列绑定时指定的路由键模式(通配符)匹配程度,将消息路由到一个或多个队列。路由键可以使用通配符符号 *(匹配一个单词)和 #(匹配零个或多个单词),允许更灵活的消息路由。用于发布/订阅模式和复杂的消息路由需求。

3、Headers Exchange:

这种交换机根据消息的标头信息(Headers)来决定消息的路由,而不是使用路由键。队列和交换机之间的绑定规则是根据标头键值对来定义的,只有当消息的标头与绑定规则完全匹配时,消息才会被路由到队列。适用于需要复杂消息匹配的场景。

4、Fanout Exchange:

这种交换机将消息广播到与之绑定的所有队列,无论消息的路由键是什么。用于发布/订阅模式,其中一个消息被广播给所有订阅者。

5、Default Exchange:

这是 RabbitMQ 默认实现的一种交换机,它不需要手动创建。当消息发布到默认交换机时,路由键会被解释为队列的名称,消息会被路由到与路由键名称相同的队列。默认交换机通常用于点对点通信,但不支持复杂的路由策略。

这些不同类型的交换机允许你在 RabbitMQ 中实现各种不同的消息路由和分发策略,以满足不同的应用需求。选择适当的交换机类型对于有效的消息传递非常重要。

如何保证消息的有序性

如图所示消息保证不了顺讯性:一个队列发送了多个消息由不同消费者去消费,由于每个消费者处理消息的速度不同,所以就造就了无序。
在这里插入图片描述

如图所示只要将多个消息顺序的发送到同一个queue中,这个queue由一个消费者进行顺序消费即可。
在这里插入图片描述

如何保证消息不丢失

消息丢失分为三种情况
1.生产端到RabbitMQ
使用confirm消息确认机制:生产者投递消息到MQ后,MQ会发送一个确认消息给生产端。
开启消息确认的方式:
channel.confirmSelect();// 开启发送方确认模式

public class NormalConfirmProducer {
    private final static String EXCHANGE_NAME = "normal-confirm-exchange";
 
    public static void main(String[] args) throws IOException, TimeoutException {
        // 创建连接
        ConnectionFactory factory = new ConnectionFactory();
        // 设置 RabbitMQ 的主机名
        factory.setHost("localhost");
        // 创建一个连接
        Connection connection = factory.newConnection();
        // 创建一个通道
        Channel channel = connection.createChannel();
        // 创建一个Exchange
        channel.exchangeDeclare(EXCHANGE_NAME, "direct");
        try {
            channel.confirmSelect();
            // 发送消息
            String message = "normal confirm test";
            channel.basicPublish(EXCHANGE_NAME, "", null, message.getBytes());
            if (channel.waitForConfirms()) {
                System.out.println("send message success");
            } else {
                System.out.println("send message failed");
                // do something else...
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
 
        // 关闭频道和连接
        channel.close();
        connection.close();
    }
}

2.RabbitMQ突然挂掉导致内存中的消息丢失
解决方案:消息持久化,需要将exchange、queue和message都进行持久化!

//exchange持久化
//第三个参数true表示这个exchange持久化
channel.exchangeDeclare(EXCHANGE_NAME, "direct", true);

//queue持久化
//第二个参数true表示这个queue持久化
channel.queueDeclare(QUEUE_NAME, true, false, false, null);

//message 持久化
//第三个参数MessageProperties.PERSISTENT_TEXT_PLAIN表示这条消息持久化
channel.basicPublish(EXCHANGE_NAME, ROUTING_KEY, 
MessageProperties.PERSISTENT_TEXT_PLAIN, 
message.getBytes(StandardCharsets.UTF_8));

3.消费端消息丢失
解决方案:消费端通过ack机制进行手动确认。
在这里插入图片描述

如何确保消息不被重复消费

首先,可以通过维护一个消息ID的集合来实现消息去重。在消费者端,如果接收到的消息ID已经在集合中,则认为该消息已经被处理过,从而避免了重复消费的问题.
此外,设计幂等性的处理逻辑也是一种有效的解决方案。幂等性意味着对系统的影响无论执行多少次都是相同的,这样即使消息被重复消费,也不会对系统状态造成影响。
另一种方法是使用定时任务和Redis来记录已接收的消息。当发送者发送消息后,如果没有收到ACK(确认),则通过定时任务重发消息。同时,在消息队列处使用Redis记录收到的消息。如果消费者从Redis中读取到的消息已经存在,则说明之前已经处理过该消息,从而避免了重复消费。RabbitMQ提供了消费者应答(ack)机制,默认情况下这个机制是自动应答的。只要消息推送到消费者就会自动ack,然后RabbitMQ删除队列中的消息。启用这一机制可以有效防止消息被重复消费。综上所述,保证消息不被重复消费的关键在于实现消息去重和幂等性处理。具体到RabbitMQ,可以通过维护消息ID集合、设计幂等性处理逻辑、使用定时任务和Redis记录已接收的消息以及利用消费者的自动应答机制来实现这一目标。这些方法可以根据实际业务场景进行选择和调整,以达到最佳的效果。

处理消息堆积

①可以动态增加消费者的数量,提高消费速度。(使用工作队列模式。)
②提高消费者消费能力,在消费者中可以使用多线程进行消费。
③可以先把消息放到redis的list缓存中,然后使用定时任务根据消费者的消费能力,定时从缓存中获取定量的消息进行发送。
④消费者使用熔断降级策略,快速对消息进行响应。

  • 11
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
自动控制节水灌溉技术的高低代表着农业现代化的发展状况,灌溉系统自动化水平较低是制约我国高效农业发展的主要原因。本文就此问题研究了单片机控制的滴灌节水灌溉系统,该系统可对不同土壤的湿度进行监控,并按照作物对土壤湿度的要求进行适时、适量灌水,其核心是单片机和PC机构成的控制部分,主要对土壤湿度与灌水量之间的关系、灌溉控制技术及设备系统的硬件、软件编程各个部分进行了深入的研究。 单片机控制部分采用上下位机的形式。下位机硬件部分选用AT89C51单片机为核心,主要由土壤湿度传感器,信号处理电路,显示电路,输出控制电路,故障报警电路等组成,软件选用汇编语言编程。上位机选用586型以上PC机,通过MAX232芯片实现同下位机的电平转换功能,上下位机之间通过串行通信方式进行数据的双向传输,软件选用VB高级编程语言以建立友好的人机界面。系统主要具有以下功能:可在PC机提供的人机对话界面上设置作物要求的土壤湿度相关参数;单片机可将土壤湿度传感器检测到的土壤湿度模拟量转换成数字量,显示于LED显示器上,同时单片机可采用串行通信方式将此湿度值传输到PC机上;PC机通过其内设程序计算出所需的灌水量和灌水时间,且显示于界面上,并将有关的灌水信息反馈给单片机,若需灌水,则单片机系统启动鸣音报警,发出灌水信号,并经放大驱动设备,开启电磁阀进行倒计时定时灌水,若不需灌水,即PC机上显示的灌水量和灌水时间均为0,系统不进行灌水。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值