rabbitmq学习笔记
一 简介
01 特点
开发语言: erlang
单机吞吐量: 万级
消息延迟: 微妙级
功能特性: 并发能力强,性能极其好,时延低,社区活跃,管理界面丰富
02 消息队列的应用场景
应用解耦,异步处理,流量削峰,消息通知
应用解耦:
之前的做法通过feign调用,现在的做法通过消息队列
异步处理:
示例:由之前的串行发短信发邮件,变成发短信和发邮件订阅消息队列
流量削峰
数据库的处理并发能力有限,由消息队列平稳的去处理消息
03 AMQP协议
AMQP( Advanced Message Queueing Protocol)协议是一个高级抽象层消息通信协议,RabbitMQ是AMQP协议的实现。架构模型如下
04 名词解释
broker: 一个中间件实例,及一个RabbitMQ 服务器
message: 消息,就是要传输的数据
producer: 消息的生产者,就是将数据发送给RabbitMQ的客户端
consumer: 消息的消费者,用户获取并处理生产者发送的数据
exchange: 交换器,消息需要从交换器按照不同的规则分发到指定的目的地(队列)
queue: 队列, 消息最终要存放到队列,然后由对应的消费者消费队列里的消息
routing key: 路由key,交换器可以根据路由规则,决定消息该发往哪里
binding key: 将路由key和队列进行绑定,(在exchange配置队列时完成)
05 四种交换机类型
4种交换器类型
Direct Exchange: 直连交换器
小结:直连交换器发送消息会根据路由和交换机的绑定关系发送到队列
Fanout Exchange: 分发交换器(扇出交换器)
小结: 分发交换器发送消息会分发至所有和其有绑定的队列中,这样消息会被多个消费者处理
Topic Exchange: 主题交换器
小结:主题交换器可以让每个队列只接收它关注的信息
可以根据路由key 进行模式匹配 有两种方式: 分别是 # 和 *
# 表示支持多个单词 单词的长度不限制 多个单词间使用.分隔
* 表示只能匹配一个单词 单词的长度不限制
Headers Exchange: 头信息交换器(了解)
头信息交换器可以实现更为复杂的匹配但性能不好,
不推荐使用,了解即可
注释
Direct Exchange: 直连交换器,如果交换器名称为"",将使用默认交换器,默认交换器不会绑定任何队列,mq会直接把route_key当做queue名称去查找
Fanout Exchange 只要和该交换机绑定的队列都会接收到消息
Topic Exchange: 主题交换器
例如exchange的 A队列的builder routing key 为a.*
符合那么发送消息的路由key如果是a.2356 或者a.456 都是可以发送到A队列,而a.456.456不可以
例如exchange的 B队列的builder routing key 为B.#
符合那么发送消息的路由key如果是b.2356 或者b.456.45564 都是可以发送到B队列
06 五种工作模式
简单模式: 消息只有一个消费者 使用默认交换器即可(direct)
工作队列模式: 消息有多个消费者,消息只可以被消费一次 使用默认交换器即可(direct)
发布订阅模式: 消息有多个消费者,而且消息会被多个消费者同时消费 使用分发交换器即可(fanout)
路由模式: 根据路由的key,将消息发送到指定的队列 使用直接交换器即可(direct)
通配符(主题)模式: 根据路由的key,进行通配符匹配,发送到指定的队列(topic) 使用主题交换器即可
07 项目中MQ的应用
商品搜索功能 数据库及索引库的一致性 商品上架 --> 发送上架消息 --> es搜索服务 --> 将上架商品存入索引库 商品下架 --> 发送下架消息 --> es搜索服务 --> 将下架商品删除
商品详情静态化,静态页面的生成延迟队列: 商品上架 --> 发送上架消息 --> 静态化服务 --> 将上架商品生成静态页
利用rabbitmq的死信队列功能实现订单延时处理
用户注册成功后向MQ中发送消息, 短信服务监听队列消息实现短信发送
监控数据的采集可以使用rabbitmq异步采集 日志信息的采集 链路追踪信息的采集
二 入门demo
01 添加父工程rabbitmq-demo
目录结构
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.8.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!-- rabbitmq起步依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
02 消息的生产者Producer
创建发送消息工程 maven工程 rabbit_producer,添加依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
配置application.yml
spring
springboot启动类(略)
发送消息
03 消息的消费者 Consumer
创建消息消费者 maven工程
设置pom 依赖,同生产者
配置yml文件
server
配置启动类
配置listen监听器
/**
* 消息监听者
* @author lyn
*/
三 MQ面试热点
mq常见问题
消息丢失,消息积压,重复消费
01 如何保证消费的可靠性传输?
主要从三个角度来分析:
生产者的发消息的可靠性
消息队列数据的可靠性
消费者消费数据的可靠性
1> 生产者发消息的可靠性
从生产者弄丢数据这个角度来看,RabbitMQ提供transaction和confirm模式来确保生产者不丢消息。
transaction事务机制(了解)
transaction机制就是说,发送消息前,开启事务(channel.txSelect()),然后发送消息,如果发送过程中出现什么异常,事务就会回滚(channel.txRollback()),如果发送成功则提交事务(channel.txCommit())。然而,这种方式有个缺点:吞吐量下降。
confirm确认机制
一旦channel进入confirm模式,所有在该信道上发布的消息都将会被指派一个唯一的ID(从1开始),一旦消息被投递到所有
匹配的队列
之后,rabbitMQ就会发送一个ACK给生产者(包含消息的唯一ID),这就使得生产者知道消息已经正确到达目的队列了。如果rabbitMQ没能处理该消息,则会发送一个Nack消息给你,你可以进行重试操作。处理Ack和Nack的代码如下所示
更改发送者配置
spring
增加rabbitmq配置类
package com.hjxr.producer.config;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.converter.SerializerMessageConverter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* RabbitMq配置类
*
* @author lyn
*/