rabbitMQ学习笔记
介绍
-
点对点式: – 消息发送者发送消息,消息代理将其放入一个队列中,消息接收者从队列中获取消息内容, 消息读取后被移出队列 – 消息只有唯一的发送者和接受者,但并不是说只能有一个接收者
-
. 发布订阅式: – 发送者(发布者)发送消息到主题,多个接收者(订阅者)监听(订阅)这个主题,那么 就会在消息到达时同时收到消息
direct点对点,fanout,topic,headers:后三者发布订阅模式
topic 的模糊匹配占位符
# :匹配一个或多个词 * :匹配不多不少恰好1个词
-
. JMS(Java Message Service)JAVA消息服务: – 基于JVM消息代理的规范。ActiveMQ、HornetMQ是JMS实现
-
. AMQP(Advanced Message Queuing Protocol) – 高级消息队列协议,也是一个消息代理的规范,兼容JMS – RabbitMQ是AMQP的实现
过程:
publisher(发布者) --> broker(服务器)–>virtual Host虚拟机(多个/xx1,/xx2第1级命名空间)–>exchange(交换器 )–binding–>queue(队列) —连接channel信道—>consumer消费者
7种模式说明,包括RPC(同步),能者多劳模式 +上面4种 说明, head模式是匹配queue的head是否跟exchange的head一致
https://blog.csdn.net/qq_39648029/article/details/108345323
关于header的匹配
队列A:绑定交换机参数是:format=pdf,type=report,x-match=all,
队列B: 绑定交换机参数是:format=pdf,type=log,x-match=any,
队列C:绑定交换机参数是:format=zip,type=report,x-match=all,
消息1发送交换机的头参数是:format=pdf,type=reprot则消息传送到队列A 消息2发送交换机的头参数是:format=pdf则消息传送到队列A和队列B 消息3发送交换机的头参数是:format=zip,type=log则消息没有匹配队列,此消息会被丢弃
关于queues里面最新版本有个type :Quorum机制
目的:达到强一致性
方法:N个节点, 1个主节点, 向x个集群节点同步数据时, 一共有1+x个节点,此时我们定义超过一半的节点是最新数据则算操作成功,所以定义只要访问一半以上的次数,就能获取到最新的版本号。
java
1.引包
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
<version>2.2.10.RELEASE</version>
</dependency>
spring:
application:
name:
rabbitmq:
localhost: 119.29.132.51
port: 5672
username: guest
password: guest
#virtual-host: #默认/ 虚拟机地址 理解成命名空间
2.使用
a.rabbitTemplate 用于操作发送跟接收消息
/**
* 1.单播 (点对点)
*/
public void sendMessage(){
//message 需要自己构造一个 消息头跟消息体,
//这个message跟上面引得sping-boot-starter-amqp 里面引得message模块有关系
//rabbitTemplate.send(exchage,routeKey,message)
//默认会将Object对象序列化后当成消息体 这个地方得conver可以替换
//默认是simpleMessageConvert new redisTemplate 构造方法里面初始化的
//这个地方有ObjectProvider<T> 其实用来注入Bean的 具体规则百度一下把
//rabbitTempate.converAndSend(exchage,routekey,Object)
//切换MessageConvert 只需要在上下文中注入对应的Bean实现就可以了 初始化rabbitTempate的时候会根据ObjectProvider来注入
}
/**
* 接收
*/
public void testReceive(){
//Object o = rabbitMqTemplate.receiveAndConvert(queueName);
}
/**
* topic
/
//-----接收消息
//通过 @RabbitListener 的 bindings 属性声明 Binding(若 RabbitMQ 中不存在该绑定所需要的 Queue、Exchange、RouteKey 则自动创建)
@RabbitListener(bindings = @QueueBinding(exchange = @Exchange(value = "${rabbit.rabbit1.exchange1:zxy.testExchange}",durable = "true", type = "topic")
,value = @Queue(value = "${rabbit.rabbit1.queue1:zxy.testQueue}",durable = "true")
,key = "zxy.#"))
public void testListener(Message message){
System.out.println(new String(message.getBody()));
}
b.amqpAdmin 用于创建队列跟交换机
c.rabbit连接多个虚拟机 疑问 能不能动态注入BEAN 你配置了几个配置项就注几个配置 template按序号规则命名
RabbitMQ 集群配置
spring.rabbitmq.first.host=node9
spring.rabbitmq.first.port=5670
spring.rabbitmq.first.username=guest
spring.rabbitmq.first.password=guest
spring.rabbitmq.second.host=localhost
spring.rabbitmq.second.port=5672
spring.rabbitmq.second.username=guest
spring.rabbitmq.second.password=guest
package com.paas.springboot.demo01;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.amqp.SimpleRabbitListenerContainerFactoryConfigurer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
@Configuration
public class RabbitConfig {
@Bean(name="firstConnectionFactory")
@Primary
public ConnectionFactory firstConnectionFactory(
@Value("${spring.rabbitmq.first.host}") String host,
@Value("${spring.rabbitmq.first.port}") int port,
@Value("${spring.rabbitmq.first.username}") String username,
@Value("${spring.rabbitmq.first.password}") String password
){
CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
connectionFactory.setHost(host);
connectionFactory.setPort(port);
connectionFactory.setUsername(username);
connectionFactory.setPassword(password);
//connectionFactory.setVirtualHost();
return connectionFactory;
}
@Bean(name="secondConnectionFactory")
public ConnectionFactory secondConnectionFactory(
@Value("${spring.rabbitmq.second.host}") String host,
@Value("${spring.rabbitmq.second.port}") int port,
@Value("${spring.rabbitmq.second.username}") String username,
@Value("${spring.rabbitmq.second.password}") String password
){
CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
connectionFactory.setHost(host);
connectionFactory.setPort(port);
connectionFactory.setUsername(username);
connectionFactory.setPassword(password);
//connectionFactory.setVirtualHost();
return connectionFactory;
}
@Bean(name="firstRabbitTemplate")
@Primary
public RabbitTemplate firstRabbitTemplate(
@Qualifier("firstConnectionFactory") ConnectionFactory connectionFactory
){
RabbitTemplate firstRabbitTemplate = new RabbitTemplate(connectionFactory);
return firstRabbitTemplate;
}
@Bean(name="secondRabbitTemplate")
public RabbitTemplate secondRabbitTemplate(
@Qualifier("secondConnectionFactory") ConnectionFactory connectionFactory
){
RabbitTemplate secondRabbitTemplate = new RabbitTemplate(connectionFactory);
return secondRabbitTemplate;
}
@Bean(name="firstFactory")
public SimpleRabbitListenerContainerFactory firstFactory(
SimpleRabbitListenerContainerFactoryConfigurer configurer,
@Qualifier("firstConnectionFactory") ConnectionFactory connectionFactory
) {
SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
configurer.configure(factory, connectionFactory);
return factory;
}
@Bean(name="secondFactory")
public SimpleRabbitListenerContainerFactory secondFactory(
SimpleRabbitListenerContainerFactoryConfigurer configurer,
@Qualifier("secondConnectionFactory") ConnectionFactory connectionFactory
) {
SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
configurer.configure(factory, connectionFactory);
return factory;
}
@Bean
public Queue firstQueue() {
System.out.println("configuration firstQueue ........................");
return new Queue("hello1");
}
@Bean
public Object secondQueue() {
System.out.println("configuration secondQueue ........................");
return new Queue("hello2");
}
}
限流配置
#在单个请求中处理的消息个数,他应该大于等于事务数量(unack的最大数量)
spring.rabbitmq.listener.simple.prefetch=2
#在@RabbitListener(queues = { HighDeviceMessage.QUEUE_NAME },concurrency = "${spring.rabbitmq.highdevice.concurrency}")配置的占位符配置
spring.rabbitmq.highdevice.concurrency=2-5
RabbitMQ的生产者消息确认(Publisher Confirms and Returns)和消费者ACK
消息应答(ack)
https://www.cnblogs.com/refuge/p/10356750.html
https://www.cnblogs.com/biehongli/p/11789098.html
关闭自动应答
boolean autoAck=false;
监听队列
channel.basicConsume(QUEUE_NAME, autoAck, defaultConsumer);
说明:在上一片博客中,我们用到了rabbitMQ的公平分发的时候,关掉了自动应答如上面所示。rabbitMQ是默认开启自动应答的,这样当rabbitMQ将消息发给消费者,就会从内存中将消息删除,这样会带来一个问题,如果消费者未处理完消息而宕机,那么消息就会丢失。所以,我们将自动应答关闭,当rabbitMQ收到消费者处理完消息的回应后才会从内存中删除消息。
消息队列持久化(durable)
boolean durable=false;
声明队列
channel.queueDeclare(QUEUE_NAME, durable, false, false, null);
说明:rabbitMQ默认将消息存储在内存中,若rabbitMQ宕机,那么所有数据就会丢失,所以在声明队列的时候可以声明将数据持久化, 但是如果已经声明了一个未持久化的队列,那么不能修改,只能将这个队列删除或重新声明一个持久化数据。
confrim(是否到达exchange) 跟returns(exchange是否到达queue)模式
https://blog.csdn.net/lvyangxue/article/details/108185236
比较好的文章
rabbitmq全面
https://www.cnblogs.com/ming-blogs/p/10920470.html1
默认登录端口
http://119.29.132.51:15672/#/
账号密码 guest/guest