目录
一、RabbitMQ入门
1.1 rabbitmq是啥?
1.2 应用场景
1.3 AMQP协议与RabbitMQ工作流程
1.4 Docker安装部署RabbitMQ
二、SpringBoot连接MQ配置
2.1 示例1
2.1 示例2 —— 发送实体
MQ(Message queue 释义):消息队列,本质上就是一个队列。
而消息队列(Message Queue)是在消息的传输过程中保存消息的容器。在消息队列中,通常有生产者和消费者两个角色。生产者只负责发送数据到消息队列,谁从消息队列中取出数据处理,他不管。消费者只负责从消息队列中取出数据处理,他不管这是谁发送的数据。
RabbitMQ是一个消息代理 - 一个消息系统的媒介。它可以为你的应用提供一个通用的消息发送和接收平台,并且保证消息在传输过程中的安全。
ribbitmq主要解决异步处理、应用解耦、流量削锋等问题,实现高性能,高可用,可伸缩和最终一致性架构
如图所示:当一个用户购买了商品,订单开始发送发货通知——>刷新商品推荐(重新计算用户的喜好)——>增加会员积分,这些时间加一起就要150ms。而使用的RabbitMQ之后,将订单的求情放到rabbitmq容器中,不需要等待其他服务处理完再返回结果,让他们自己去rabbitmq排队处理。
如图所示:假设有系统B、C、D都需要系统A的数据,于是系统A调用三个方法发送数据到B、C、D。这时,系统D不需要了,那就需要在系统A把相关的代码删掉。假设这时有个新的系统E需要数据,这时系统A又要增加调用系统E的代码。为了降低这种强耦合,就可以使用MQ,系统A只需要把数据发送到MQ,其他系统如果需要数据,则从MQ中获取即可。
应用场景:秒杀活动,一般会因为流量过大,导致流量暴增,应用挂掉。为解决这个问题,一般需要在应用前端加入消息队列
如图所示:这其实是MQ一个很重要的应用。假设用户在某一段时间请求数暴增,有5000个请求发送过来,系统这时就会发送5000条SQL进入MySQL进行执行,MySQL对于如此庞大的请求当然处理不过来,MySQL就会崩溃,导致系统瘫痪。如果使用MQ,系统不再是直接发送SQL到数据库,而是把数据发送到MQ,MQ短时间积压数据,然后由消费者每次拉取2000条进行处理,防止在请求峰值时期大量的请求直接发送到MySQL导致系统崩溃。
AMQP:一个提供统一消息服务的应用层标准高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计。基于此协议的客户端与消息中间件可传递消息,并不受客户端/中间件不同产品,不同的开发语言等条件的限制。
像RabbitMQ这样的消息队列实现是基于AMQP协议的,如果先了解一条消息从投递到消息队列到被消费者消费的生命周期,再来深入了解RabbitMQ的使用那就很easy。
工作过程:
1.生产者发布消息,经由交换机。
2.交换机根据路由规则将收到的消息分发给与该交换机绑定的队列。
3.最后消息中间件会将消息投递给订阅了此队列的消费者,或者消费者按照需求自行获取。
4.消费者在成功处理消息后向 RabbitMQ 发送确认(ACK)。这告诉 RabbitMQ 可以安全地从队列中删除该消息。如果消费者在处理消息时发生错误,RabbitMQ 可以将消息重新分发给其他消费者。
可靠性与持久性:RabbitMQ 提供了消息的持久性选项,允许将消息和队列标记为持久的。这确保即使 RabbitMQ 服务器重启,消息和队列也不会丢失。
技术选型:
docker pull rabbitmq:management
注意获取镜像的时候要获取management版本的,不要获取last版本的,management版本的才带有管理界面。
1、创建宿主机目录
防火墙开放端口:
firewall-cmd --zone=public --add-port=5672(15672)/tcp --permanent
docker run -itd \
--name my-rabbitmq \
-p 5672:5672 -p 15672:15672 \
-v /home/rabbitmq:/var/lib/rabbitmq \
--hostname my-rabbitmq-host \
-e RABBITMQ_DEFAULT_VHOST=my_vhost \
-e RABBITMQ_DEFAULT_USER=ycxw \
-e RABBITMQ_DEFAULT_PASS=123 \
--restart=always \
rabbitmq:management
--hostname:主机名(RabbitMQ的一个重要注意事项是它根据所谓的 “节点名称” 存储数据,默认为主机名)
-e:指定环境变量:
- RABBITMQ_DEFAULT_VHOST:默认虚拟机名
- RABBITMQ_DEFAULT_USER:默认的用户名
- RABBITMQ_DEFAULT_PASS:默认用户名的密码
1、创建项目:publisher 生成者 , consumer 消费者
rabbitmq需要导入amqp依赖
org.springframework.boot spring-boot-starter-amqp
2、rabbitmq连接配置
生产者端口:8888 消费者端口:6666
注意!!!:
需等生产者创建队列后并发送过一次信息被rabbitmq接受,消费者才能启动项目,不然会报错找不到连接的队列名
server:
port: 8888
spring:
rabbitmq:
#虚拟机地址
host: 192.168.83.129
port: 5672
#rabbitmq注册用户与密码
username: ycxw
password: 123
virtual-host: my_vhost
3、创建Rabbit配置类RabbitConfig,配置类主要用来配置队列、交换器、路由等高级信息
package com.ycxw.publisher.demos;
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");
}
}
4、创建消息产生者类
package com.ycxw.publisher.demos;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class Sender {
@Autowired
private AmqpTemplate rabbitTemplate;
@RequestMapping("/send1")
public String sendFirst() {
/*向消息队列发送消息 converAndSend(队列名,发送的信息)*/
rabbitTemplate.convertAndSend("firstQueue", "Hello World");
return "";
}
}
5、编写接受队列的消息方法
package com.ycxw.consumer.demos;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
@Component
@SuppressWarnings("all")
@Slf4j
@RabbitListener(queues = "firstQueue") //监听消息队列
public class Receiver {
//处理接受的信息
@RabbitHandler
public void process(String msg) {
log.warn("接收到:" + msg);
}
}
6、测试
生产者发起请求:
rabbitmq管理界面查看数据:
消费者接受信息:
注意!!!:
- 处理不同请求许再创建一个队列
- 实体需进行序列化才可发送
- 发送实体,需要两个模块的实体必须同名同包下
1、创建实体类
package com.ycxw.publisher.demos;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
//实现spring自带序列化接口
@SuppressWarnings("all")
@AllArgsConstructor
@NoArgsConstructor
@Data
public class User implements Serializable {
private String username;
private String userpwd;
}
2、创建队列(生产者)
3、 编写发送信息方法
注入ObjectMapper类将实体装换成json格式的数据进行发送
4、接受信息(消费者)
package com.ycxw.consumer.demos;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
@SuppressWarnings("all")
@Slf4j
@RabbitListener(queues = "secondQueue") //监听消息队列
public class Receiver2 {
@Autowired
private ObjectMapper objectMapper;
//处理接受的信息
@RabbitHandler
public void process(String json) throws JsonProcessingException {
//将接受的json数据转换成实体
User ycxw = objectMapper.readValue(json, User.class);
log.warn("接收到:" + ycxw);
}
}
5、测试
消费者接受的信息