一、什么是消息队列(RabbitMQ)?
服务之间最常见的通信方式是直接调用彼此来通信 , 消息从一端发出后立即就可以达到另一端 , 称为即时消息通讯 ( 同步通信 )
消息从某一端发出后 , 首先进入一个容器进行临时存储 , 当达到某种条件后 , 再由这个容器发送给另一端 , 称为延迟消息通讯 ( 异步通信 )
案例分析
小红希望小明多读书 , 常寻找好书给小明看 , 之前的方式是这样:小红问小明什么时候有空 , 把书给小明送去 , 并亲眼监督小明读完书才走 . 久而久之 , 两人都觉得麻烦 .
后来的方式改成了:小红对小明说「我放到书架上的书你都要看」 , 然后小红每次发现不错的书都放到书架上 , 小明则看到书架上有书就拿下来看
书架就是一个消息队列,小红是生产者,小明是消费者
带来的好处
1. 小红想给小明书的时候 , 不必问小明什么时候有空 , 亲手把书交给他了 , 小红只把书放到书架上就行了 . 这样小红小明的时间都更自由 .
2. 小红相信小明的读书自觉和读书能力 , 不必亲眼观察小明的读书过程 , 小红只要做一个放书的动作 , 很节省时间 .
3. 当明天有另一个爱读书的小伙伴小强加入 , 小红仍旧只需要把书放到书架上 , 小明和小强从书架上取书即可
4. 书架上的书放在那里 , 小明阅读速度快就早点看完 , 阅读速度慢就晚点看完 , 没关系 , 比起小红把书递给小明并监督小明读完的方式 , 小明的压力会小一些
消息队列特点
1. 解耦 : 每个成员不必受其他成员影响 , 可以更独立自主 , 只通过一个简单的容器来联系 .
2. 提速 : 小红选只要做一个放书的动作 , 为自己节省了大量时间 .
3. 广播 : 小红只需要劳动一次 , 就可以让多个小伙伴有书可读 , 这大大地节省了她的时间 , 也让新的小伙伴的加入成本很低 .
4. 错峰与流控 : 小红给书的频率不稳定 , 如果今明两天连给了五本 , 之后隔三个月才又给一本 , 那小明只要在三个月内从书架上陆续取走五本书读完就行了 , 压力就不那么大了
Email邮件案例分析
有大量用户注册你的软件 , 再高并发情况下注册请求开始出现一些问题 .
例如邮件接口承受不住 , 或是分析信息时的大量计算使 cpu 满载 , 这将会出现虽然用户数据记录很快的添加到数据库中了 , 但是却卡在发邮件或分析信息时的情况 .
导致请求的响应时间大幅增长 , 甚至出现超时 , 这就有点不划算了 . 面对这种情况一般也是将这些操作放入消息队列 ( 生产者消费者模型 ), 消息队列慢慢的进行处理 , 同时可以很快的完成注册请
求 , 不会影响用户使用其他功能
二、消息队列技术选型
三、Docker安装部署RabbitMQ
1.注意获取镜像的时候要获取 management 版本的 , 不要获取 last 版本的 ,management 版本的才带有管理界面
2.创建rabbit容器并映射ip以及挂载(需要保存)
--hostname :主机名 (RabbitMQ 的一个重要注意事项是它根据所谓的 “ 节点名称 ” 存储数据 , 默认为主机名 )
-e :指定环境变量 :
RABBITMQ_DEFAULT_VHOST :默认虚拟机名
RABBITMQ_DEFAULT_USER :默认的用户名
RABBITMQ_DEFAULT_PASS :默认用户名的密码
3. 登录后台
四、springboot连接配置
1.使用admin登录后创建一个新用户(赋予管理员权限)
2.springboot项目搭建
创建provider和consumer模块继承父类
3.父类导入amqp依赖
4.provider中yml文件
5.创建RabbitConfig类
每次运行时创建一个队列
package com.example.provider;
import org.springframework.amqp.core.Queue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@SuppressWarnings("all") public class RabbitConfig {
@Bean
public Queue firstQueue() { return new Queue("firstQueue"); } }
6.创建Sender类
模拟队列中的发送消息
package com.example.provider;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
@SuppressWarnings("all") public class Sender {
@Autowired
private AmqpTemplate rabbitTemplate;
public void sendFirst() {
rabbitTemplate.convertAndSend("firstQueue", "Hello World");
}
}
7.在测试类调用senderFirst方法
模拟消费者下单后给生产者发送消息
package com.example.provider;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class ProviderApplicationTests {
@Autowired
private Sender sender;
@Test
void contextLoads() {
sender.sendFirst();
}
}
8.此时RabbitMQ内出现一条消息队列
9. 在consumer的yml文件中配置相关信息
注意:端口号与provider不一致
10.在consumer中创建Receiver类
模拟生产者接收消息
@RabbitListener表示监听消息队列
package com.example.consumer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
@SuppressWarnings("all")
@Slf4j
@RabbitListener(queues = "firstQueue") public class Receiver {
@RabbitHandler
public void process(String msg) {
log.warn("接收到:" + msg);
}
}
11.运行consumer模块就可以接收消息了
12.为了使消息变成动态的,写一个用户类
package com.example.provider;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@SuppressWarnings("all")
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User{
private String username;
private String userpwd;
}
13.重写sendFirst方法
14.将provider的测试类以及Receiver类中的参数改成sendFirst中的一样
15.运行即可