rabbitmq学习
rabbitmq学习,rabbitmq教程,rabbitmq安装
docker 按照rabbitmq
docker run --name rabbitmq -d -p 15672:15672 -p 5672:5672 rabbitmq:3.10-management
官方地址:https://www.rabbitmq.com/download.html
作用:
1、削蜂,
2、解耦
3、异步处理
核心概念:
交换机、队列、信道
交换机默认有4个类型:
direct:1条信息仅允许发送到1个队列。(RoutingKey匹配队列名)
fanout:1条信息发送到所有绑定的队列。(忽略RoutingKey)
header:1条信息发送到匹配的队队。(用header头部数据匹配)
topic:1条信息发送到匹配RoutingKey规则的队列。(一般用#和*通配符)
通配符号#(无视.点号)和*(遇到.点号则中止)说明:
topic.#那么这个队列会接收topic开头的消息,如topic.hello.world topic.*那么这个队列只接收topic开头后面一个的消息,如topic.hello
参考:https://www.cnblogs.com/cyq1162/p/16603461.html
官网网址:https://www.rabbitmq.com/download.html
docker安装:
docker run -it --rm --name rabbitmq -p 5672:5672 -p 15672:15672 rabbitmq:3.12-management
默认用户名密码:guest,guest
网页访问地址:http://localhost:15672
默认是存到内存中的,不持久化
队列是否进行多个消费者进行消费
模式:
队列模式:
消息丢失怎么办:应答模式:自动应答,手动应答。
队列持久化:d
消息持久化:
不公平分发:Qos
预取值 prefetch
消息确认原理:
发布确认:单个确认、cofitureselect()、批量确认、异步确认t(通过监听器实现)、chaal.
通过map实现,删除确认的消息
消息确认:
交换机类型:
fanout:广播,发布订阅模式
direct交换机:路由模式,多重绑定
topic交换机
当一个队列绑定#,就接收所有消息,
如果当中没有#和*号,就是direct啦
*代表一个
#代表0或者多个
死信队列:可以一定时间去做某个事情
ttl过期
延迟队列场景
生产者到交换机,确认机制
优先级队列,消息需要设置优先级,必须先把消息发送到队列中,然后在消费。
惰性队列
消费者宕机,大量消息没有消费
rabbitmq缺点:
保证mq没有问题、一致性问题、
镜像队列:添加策略
如何保证rabbitmq消息不被丢失:
生产者到rabbitmq:通过开启确认机制
rabbitmq丢失:通过持久化
消费者丢失:消费者确认机制
springboot配置文件
spring: rabbitmq: host: localhost port: 5672 virtual-host: / username: guest password: guest publisher-confirm-type: correlated publisher-returns: true template: mandatory: true retry: #发布重试,默认false enabled: true #重试时间 默认1000ms initial-interval: 1000 #重试最大次数 最大3 max-attempts: 3 #重试最大间隔时间 max-interval: 10000 #重试的时间隔乘数,比如配2,0 第一次等于10s,第二次等于20s,第三次等于40s multiplier: 1 listener: # 默认配置是simple type: simple simple: # 手动ack Acknowledge mode of container. auto none acknowledge-mode: manual #消费者调用程序线程的最小数量 concurrency: 10 #消费者最大数量 max-concurrency: 10 #限制消费者每次只处理一条信息,处理完在继续下一条 prefetch: 1 #启动时是否默认启动容器 auto-startup: true #被拒绝时重新进入队列 default-requeue-rejected: true
如何防止重复消费:
通过全局id方式,幂等性:一次或者多次结果都是一样的
@Component @RabbitListener(queues = RabbitMqConfig.ORDER_QUEUE, ackMode = "MANUAL") public class OrderConsumer { @Autowired private OrderService orderService; @RabbitHandler public void handleMessage(OrderMessage orderMessage, Channel channel, @Header(AmqpHeaders.DELIVERY_TAG) long tag) throws IOException { try { orderService.handleOrder(orderMessage); // 手动确认消息已被消费 channel.basicAck(tag, false); } catch (Exception e) { // 出现异常,拒绝消息并将其返回到队列中重新处理 channel.basicReject(tag, true); e.printStackTrace(); } } }
可以在消息生产者服务中设置一个消息id,然后在消费者监听到消息后获取该id,再去查询这个id是否存在。如果不存在,则正常消费消息,并将消息的id存入数据库或者Redis中。如果存在,则丢弃此消息。例如:
// 消息生产者服务 public void sendMessage() { String messageId = UUID.randomUUID().toString(); // 将消息id和消息体一起发送 rabbitTemplate.convertAndSend("exchange", "routingKey", message, new CorrelationData(messageId)); } // 消息消费者服务 @RabbitListener(queues = "queue") public void handleMessage(Message message, Channel channel) throws Exception { String messageId = message.getMessageProperties().getCorrelationId(); // 先去查询这个id是否存在 if (!redisTemplate.opsForValue().setIfAbsent(messageId, "")) { // 如果存在则丢弃此消息 return; } // 正常消费消息 // ... }
多个消费者消费同一条数据--交换机fanout模式
配置示例:
import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class RabbitConfig {
//供平台使用
public static String QUEUE_NAME_PLAT = "environmentQueuePlat";
//供一标段使用
public static String QUEUE_NAME_1 = "environmentQueue1";
public static String EXCHANGE_NAME = "topicEnvironmentExchange";
//供平台使用
/**
* @params1 :队列名称
* @params2 :队列是否持久化(如果是,则重启服务不会丢失)
* @params3 :是否是独占队列(如果是,则仅限于此连接)
* @params4 :是否自动删除(最后一条消息消费完毕,队列是否自动删除)
*/
@Bean
public Queue topicQueuePlat() {
//声明一个耐用队列
return new Queue(QUEUE_NAME_PLAT, true,false,false);
}
/**
* @params1 :队列名称
* @params2 :队列是否持久化(如果是,则重启服务不会丢失)
* @params3 :是否是独占队列(如果是,则仅限于此连接)
* @params4 :是否自动删除(最后一条消息消费完毕,队列是否自动删除)
*/
//供一标段使用
@Bean
public Queue topicQueue1() {
//声明一个耐用队列
return new Queue(QUEUE_NAME_1, true,false,false);
}
/**
* @params1 :交换机名称
* @params2 :是否持久化
* @params4 :是否自动删除
*/
@Bean
public FanoutExchange topicExchange() {
return new FanoutExchange(EXCHANGE_NAME,true,false);
}
@Bean
public Binding topicQueueBind() {
return BindingBuilder.bind(topicQueuePlat()).to(topicExchange());
// .with("env.*");
}
@Bean
public Binding topicBinding1Bind() {
return BindingBuilder.bind(topicQueue1()).to(topicExchange());
// .with("env.*");
}
}
生产者示例:
//因为是fanout广播模式,所以不用配置路由键。 rabbitTemplate.convertAndSend(RabbitConfig.EXCHANGE_NAME, "", sendData);
消费者示例:
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson2.JSON;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.zygh.hzhw.manage.entity.clickhouse.EnvironmentData;
import com.zygh.hzhw.manage.service.EnvironmentDataService;
import com.zygh.hzhw.manage.vo.EnvironmentDataVO;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.core.ExchangeTypes;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* 接收空气传感器数据
*/
@Component
public class EnvironmentDataConsumer {
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Autowired
private ObjectMapper objectMapper;
@Autowired
private EnvironmentDataService environmentDataService;
// @RabbitListener(queues = "queue1")
@RabbitListener(queues = {"environmentQueuePlat"})
public void getData(Message message) {
try {
String result = new String(message.getBody(), "utf-8");
EnvironmentDataVO environmentDataVO = JSONObject.parseObject(result, EnvironmentDataVO.class);
//存数据库
EnvironmentData environmentData = new EnvironmentData();
environmentData.setAmmonia(environmentDataVO.getAmmonia()==null?0:Double.valueOf(environmentDataVO.getAmmonia()))
.setHumidity(environmentDataVO.getHumidity()==null?0:Double.valueOf(environmentDataVO.getHumidity()))
.setCode(environmentDataVO.getCode()).setHydrogen(environmentDataVO.getHydrogen()==null?0:Double.valueOf(environmentDataVO.getHydrogen()))
.setCreateTime(environmentDataVO.getCreateTime()).setPm25(environmentDataVO.getPm25()==null?0:Double.valueOf(environmentDataVO.getPm25()))
.setVoc(environmentDataVO.getVoc()==null?0:Double.valueOf(environmentDataVO.getVoc()))
.setTemperature(environmentDataVO.getTemperature()==null?0:Double.valueOf(environmentDataVO.getTemperature()));
environmentDataService.save(environmentData);
//最新数据更新到redis中
try {
String json = objectMapper.writeValueAsString(result);
if(StringUtils.isNoneBlank(environmentDataVO.getCode())){
stringRedisTemplate.opsForValue().set(environmentDataVO.getCode(), json);
}
channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
} catch (Exception e) {
* 有异常就拒收消息
* basicNack(long deliveryTag, boolean multiple, boolean requeue)
* requeue:true为将消息重返当前消息队列,重新发送给消费者;
* false将消息丢弃
*/
channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, true);
e.printStackTrace();
}
}
}
rabbitmq和mqtt区别:
RabbitMQ和MQTT都有各自的使用场景。
RabbitMQ是一个开源的消息队列系统,它使用Erlang语言开发,基于AMQP协议来实现。AMQP的主要特征是面向消息、队列、路由(包括点对点和发布/订阅)、可靠性、安全。RabbitMQ的适用场景包括解耦(为面向服务的架构提供基本的最终一致性实现)。例如,在用户下单后,订单系统需要通知库存系统,传统的做法是订单系统调用库存系统的接口,而使用RabbitMQ后,订单系统和库存系统可以各自处理自身的任务,通过RabbitMQ进行消息的传递,无需直接调用。
MQTT是一个轻量级的消息传递协议,常用于物联网领域。它的特点包括发布/订阅消息传递模式、基于TCP的可靠传输、轻量级和低功耗,适用于设备间的通信。因此,MQTT适用于需要长时间运行、低功耗和可靠的消息传递的物联网设备场景。
总结来说,RabbitMQ适用于需要高可靠性、安全性和灵活性的消息队列应用场景,而MQTT适用于需要轻量级、低功耗和可靠的消息传递的物联网设备场景。
学习参考:https://www.bilibili.com/video/BV1cb4y1o7zz?p=39&spm_id_from=pageDriver&vd_source=f97080956039c326589b5b26607d960b
实战教程参考:https://developer.aliyun.com/article/1228815?spm=a2c6h.28137022
概念参考:http://wed.xjx100.cn/news/165090.html?action=onClick
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
2021-07-30 java代码规范