认识消息队列
1、同步调用与异步调用?
同步调用:A服务调用B服务,需要等待B服务执行完毕的返回值,A服务才可以继续往下执行
同步调用实例:REST(Ribbin\Feign)和RPC(Dubbo)
异步调用:A服务调用B服务,而无需等待B服务的执行结果,也就是说在B服务执行的同时A服务可以继续往下执行
异步调用实例:消息队列
2、消息队列概念?
消息队列是一个存放消息的容器,是应用程序之间的通信方法,只需要读写出入队列的消息来进行通信,无需专用连接来链接它们。
3、消息队列优缺点?
优点:
①解耦
②异步
③削峰
缺点:
①系统可用性降低
②系统复杂性提高
③数据一致性问题
RabbitMQ
1、rabbitmq的逻辑结构
逻辑结构包含:用户、虚拟主机、队列
2、rabbitmq启动事项
需要进入rabbitmq的sbin目录
cd rabbitmq_server-3.7.0/sbin
./rabbitmq-server //启动rabbitmq
ps aux|grep rabbit //查看进程(查看rabbitmq进程是否启动)
./rabbitmq-plugins enable rabbitmq_management //启动rabbitmq的管理系统插件
netstat -tlnp //查看放行的端口
firewall-cmd --add-port=15672/tcp --permanent //放行15672端口
firewall-cmd --add-port=5672/tcp --permanent //放行5672端口
systemctl stop firewalld //也可以直接关闭防火墙
ifconfig //查看当前虚拟机ip地址
查出的地址:15672 //对应的rabbitmq地址
注意:.表示执行该文件,./表示执行当前目录下的某个文件
3、rabbitmq用户管理(命令行方式)
./rabbitmqctl add_user tao 123456 //添加用户,用户名为tao,密码为123456
./rabbitmqctl set_user_tags tao administrator //设置用户权限为administrator
4、rabbitmq的六种模式
①简单模式
生产者将消息发送到队列,一个消费者从队列中取消息,一条消息对应一个消费者
②工作模式
多个消费者尝试接收同一条消息,但是最终只能有一个消费者获取到
③订阅模式
多个消费者同时获取同一条消息,生产者将消息发送到交换机,消费者将自己对应的队列注册到交换机。当生产者发送消息后,所有注册的队列的消费者都可以接收到消息
④路由模式
生产者将消息发送到交换机,消费者的队列在将自己绑定到交换机的时候设置一个key,生产者发送key格式的消息,对应key格式的消费者才能接收消息
⑤Topic模式
⑥RPC模式
5、rabbitmq消息的可靠性(事务、消息确认机制、return机制)
开启事务,会严重导致处理效率低下。
消息确认机制:确认消息是否从发送者发送到交换机
return机制:确认消息是否从交换机分发到队列
6、rabbitmq的消息延迟实现
延迟队列:消息进入到队列后,延迟指定时间才能被消费者消费。
rabbitmq队列不支持延迟队列功能, 但是可以通过TTL(Time To Live)特性模拟延迟队列的功能。
TTL:存活时间(可以设置队列或消息的存活时间,一般设置队列的存活时间)
注:A服务将消息发送到死信队列,消息超时之后,死信队列将消息发送到queue2队列,被B服务消费
delay_exchange:交换机
delay_queue1:死信队列(key为k1)
delay_queue2:消息队列(key为k2)
springboot整合rabbitmq
1、步骤
①导入依
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
②配置application.yml文件
server:
port: 9001
spring:
application:
name: producer
rabbitmq:
host: 192.168.224.129
port: 5672
virtual-host: host1
username: tao
password: 123456
③发送消息(生产者服务)
@Service
public class TestService {
@Autowired
private AmqpTemplate amqpTemplate;
public void sendMsg(String msg){
//1.发送消息到队列
amqpTemplate.convertAndSend("queue1",msg);
// //2.发送消息到交换机(订阅)
// amqpTemplate.convertAndSend("ex1","",msg);
//
// //3.发送消息到交换机(路由)
// amqpTemplate.convertAndSend("ex2","a",msg);
}
}
④接收消息(消费者服务)
@Service
//@RabbitListener(queues = {"queue1","queue2"})
@RabbitListener(queues = {"queue1"})
public class ReceiveMsgService {
@RabbitHandler
public void receiveMsg(String msg){
System.out.println("接收Msg:"+msg);
}
}
2、使用rabbitmq传递对象
rabbitmq是消息队列,发送和接收都是字符串、字节数据或者序列化对象。
①使用序列化对象传递(对象实现Serializable接口,可以直接传递对象)
生产者
@Service
public class TestService {
@Autowired
private AmqpTemplate amqpTemplate;
public void sendMsg(String msg){
amqpTemplate.convertAndSend("queue1",goods);
}
}
消费者
@Service
@RabbitListener(queues = {"queue1"})
public class ReceiveMsgService {
@RabbitHandler
public void receiveMsg(Goods goods){
System.out.println("接收Msg:"+goods);
}
}
②使用序列化数组传递(对象也需要实现Serializable接口)
生产者
@Service
public class TestService {
@Autowired
private AmqpTemplate amqpTemplate;
public void sendMsg(Goods goods){
byte[] bytes= SerializationUtils.serialize(goods);
amqpTemplate.convertAndSend("queue1",bytes);
}
}
消费者
@Service
@RabbitListener(queues = {"queue1"})
public class ReceiveMsgService {
@RabbitHandler
public void receiveMsg(byte[] bytes){
Goods goods = (Goods)SerializationUtils.deserialize(bytes);
System.out.println("接收Msg:"+goods);
}
}
③使用Json字符串传递
生产者
@Service
public class TestService {
@Autowired
private AmqpTemplate amqpTemplate;
public void sendMsg(Goods goods) throws JsonProcessingException{
ObjectMapper objectMapper = new ObjectMapper();
String string = objectMapper.writeValueAsString(goods);
amqpTemplate.convertAndSend("queue1",string );
}
}
消费者
@Service
@RabbitListener(queues = {"queue1"})
public class ReceiveMsgService {
@RabbitHandler
public void receiveMsg(String string) throws JsonProcessingException{
ObjectMapper objectMapper = new ObjectMapper();
Goods goods = objectMapper.reaValue(string,Goods.class);
System.out.println("接收Msg:"+goods);
}
}
3、springboot中的队列和交换机创建or绑定
@Configuration
public class RabbitMQConfiguration {
//创建队列queue9
@Bean
public Queue queue9() {
return new Queue("queue9");
}
//创建队列queue10
@Bean
public Queue queue10() {
return new Queue("queue10");
}
//创建订阅模式交换机
@Bean
public FanoutExchange ex5(){
return new FanoutExchange("ex5");
}
//创建路由模式交换机
@Bean
public DirectExchange ex6(){
return new DirectExchange("ex6");
}
//绑定队列queue9到订阅模式交换机
@Bean
public Binding bindingQueue9(Queue queue9, Queue queue10, DirectExchange ex6){
return BindingBuilder.bind(queue9).to(ex6).with("k1");
}
//绑定队列queue10到订阅模式交换机
@Bean
public Binding bindingQueue10(Queue queue9, Queue queue10, DirectExchange ex6){
return BindingBuilder.bind(queue10).to(ex6).with("k1");
}
}
4、springboot中实现消息确认机制与return监听机制
server:
port: 9001
spring:
application:
name: producer
rabbitmq:
host: 192.168.224.129
port: 5672
virtual-host: host1
username: tao
password: 123456
publisher-confirm-type: simple //使用return监听机制
publisher-returns: true //开启消息确认模式
接收是否消息确认、return机制的返回信息
@Component
public class PublisherConfireAndReturnConfig implements RabbitTemplate.ConfirmCallback, RabbitTemplate.ReturnCallback {
Logger logger = LoggerFactory.getLogger(PublisherConfireAndReturnConfig.class);
@Resource
private RabbitTemplate rabbitTemplate;
@PostConstruct
public void initMethod(){
rabbitTemplate.setConfirmCallback(this);
rabbitTemplate.setReturnCallback(this);
}
@Override
public void confirm(CorrelationData correlationData, boolean ack, String s) {
if(ack){
logger.info("--------消息发送(到交换机)成功");
}else{
logger.warn("--------消息发送(到交换机)失败");
}
}
@Override
public void returnedMessage(Message message, int i, String s, String s1, String s2) {
logger.info("~~~~~~~~消息发送到交换机但未分发到队列!!!");
}
}