RabbitMQ消息队列
默认账号密码:guest
cmd启动进入安装目录的sbin目录启动rabbitmq_management管理界面:.\rabbitmq-plugins enable rabbitmq_management。
管理界面rabbitmq_management管理界面启动访问路径:localhost:15672
已声明的队列不能在进行持久化修改。
一个队列只能有一个事务模式。
channel.basicPublish(交换机名,路由名或队列名,props,body);发送消息到交换器或队列,props和body为消息主体。
Channel.queueDeclare(队列名,持久化,独占,不被监听后自动删除队列,null);声明队列及队列属性赋值。
Channel.basicConsume(队列名,是否自动签收,回调函数);监听队列的消息。
解决问题
消息队列解决了:异步处理、应用解耦、流量削峰、日志处理。
spring通过AMQP协议通信与rabbitmq通信。
Virtual hosts
相当于mysql的db,一般/开头。创建用户后需要分配给他Virtual hosts,才可以进行登录。
Simple queue简单队列
一个生产者,一个消费者。一对一。
不足:耦合性高,生产者一一对应消费者,如果多个消费者消费队列中消息,这时候就不行了,队列名变更就得同时变更。
Work queues工作队列
一个生产者,多个消费者。一对多。
出现原因:simple队列是一一对应的,而我们实际开发,生产者发送消息是毫不费力的,而消费者一般是要更业务相结合的,消费者接收到消息需要处理,可能需要花费时间,这时候队列就会积压很多消息。
分发方式:轮询分发(round-robin),轮流发放。
公平分发(fair dispatch):生产者在消费者接受到消息获得回执后在发送,消费者处理完消息后发送回执给生产者在接受消息。
channel.basicQos(1); //每次只往消费者发送一条消息 收到消费者确认消息后在发送消息。
channel.basicAck(envelope.getDeliveryTag(),false); //告诉生产者已经消息接收完成。
channel.basicConsume的第二个参数设置为false为手动应答。True为自动回复。
公平分发必须改为手动确认消息。
消息应答
channel.basicConsume的第二个参数设置为false为手动应答。True为自动回复。auto-declare
自动处理一旦杀死正在处理消息的消费者,消息会丢失。将channel.basicConsume设置为false则不会丢失消息,处理完成会发生回执,没发生回执则不会删除消息,当消费者处理消息是挂了,rabbitmq会将消息发给其他消费者。
消息持久化
channel.queueDeclare(QUEUE_NAME,false,false,false,null);
第二个参数为持久化,durable
已声明的队列不能在进行参数改动。
订阅模式
生产者将消息发给交换机,队列绑定交换机(exchange),交换机将消息推给队列,消费者监听队列,实现一个消息被多个消费者消费。
交换机没有存储能力,只有队列有存储能力,没有队列绑定交换机,数据则会丢失。
消费者获得交换机消息需将交换机和队列绑定。
交换机接收生产者的消息并推送到队列。
channel.basicPublish第一个参数不填为匿名转发,订阅模式填一个交换机名。
channel.basicPublish第二个参数为路由名,通过路由名匹配交换机和队列。
交换机
交换机接收生产者的消息并推送到队列。
交换机类型:fanout:不处理路由键,所有绑定了的队列都可以从中获取消息。
Direct:处理路由键,队列获取消息需匹配路由名key。
交换器不声明类型则为默认,有消费则消费,没消费则抛弃。
路由模式 routing
生产者channel.basicPublish第二个参数为路由名。
消费者channelqueueBind第三个参数为队列路由key,绑定多个路由key写多个channel.queueBind。
主体模式 topic
将路由键和模式匹配。用符号匹配。 #匹配多个,*匹配一个。
消息确认机制(事务+confirm)
生产者怎么确认消息到达服务器:
1、 AMQP实现了事务机制
2、 Confirm模式
事务机制
1、 Txselect:用于将channal设置成transaction模式。
2、 Txcommit:提交事务
3、 Txrollback;回滚事务
都是对生产者的操作。这种模式很耗时,降低了rabbitmq的吞吐量。
Confirm
对生产者的操作,开启此模式,所有在此信道发布的消息会带一个唯一标识,消息被投到队列,rabbitmq会发生确认信息给生产者。Confirm是异步的。
开启confirm模式:channel.confirmSelect(); 、
普通模式:发一条调用一次channel.waitForConfirms()。并行
批量模式:发一批调用一次channel. waitForConfirmsOrDie(),一次发送发送错误终止后续所有。并行
异步模式:提供一个回调方法。调用channel.addConfirmListener()方法。ConfirmListener回调方法只包含一个deliveryTag(当前channel发出的消息序号),我们需要自己为每一个channel维护一个unconfirm消息序号集合,每publish一条数据,集合中元素+1,没回调一次handleAck方法,unconfirm集合删掉相应的一条(multiple=false)或多条(multiple=true)记录。从程序运行效率上看,这个unconfirm集合最好采用有序集合sortedSet存储结构。
集成spring
AMQP核心概念
Server:又称Broker,接受客户端的连接,实现AMQP实体服务。
Connection:连接,应用程序与Broken的网络连接。
Channel:网络信道,几乎所有的操作都在channel中进行,channel是进行消息读写的通道。客户端可建立多个channel,每个channel代表了一个会话任务。
Message:消息,服务器和应用程序之前传送的数据,由properties和body组成。Properties可以对消息进行修饰,比如消息的优先级、延迟等高级特性;body则就是消息体内容。
Virtual host:虚拟地址,由于进行逻辑分离,最上层的消息路由。一个virtual host里面可以有若干个exchange和queue,同一个virtual host里面不能有相同名称的exchange或queue。
Exchange:交换机,接受消息,根据路由键转发消息到绑定的队列。
Binding:exchange和queue之间的虚拟连接,binding中可以包含routing key。
Routing key:一个路由规则,虚拟机可用它来确定如何路由一个特定消息。
Queue:也称为message queue,消息队列,保存消息并将它们转发给消费者。
高级特性
消息如何保障100%的投递成功
生产端的可靠性投递
保障消息的成功发出。
保障MQ节点的成功接收。
发送端收到MQ 节点(broker)确认应答。
完善的消息进行补偿机制。
解决方案
消息落库,对消息状态进行打标。耗性能
消息的延迟投递,做二次检查,回调检查。不保证可靠性,保证可用性。
幂等性
一个操作执行多次后结果都是相同的。
消费端-幂等性保障
消息永远不会消费多次。
幂等性操作
唯一ID+指纹码,利用数据库主键去重。实现简单,高并发有数据库写入瓶颈。
利用redis的原子性实现。
Confirm确认消息流程
生产者发送消息后,confirm listener监听队列回执,队列接受到后发送回执。
调用channel.confirmSelect(),在调用channel.addConfirmListener(new ConfirmListener() 。
Return 消息机制
处理一些不可路由的消息。
Mandatory:设置为true,则监听器会监听路由不可达的消息,然后后续出路,设置为false,broker端自动删除该消息。
消费端限流
channel.basicQos(1);限制消费端一次消费一条消息。配合channel.basicAck(envelope.getDeliveryTag(),false),使用basicConsume第二个参数为false。
channel.basicQos(prefetchSize,prefetchCount,global)参数详解:
channel.basicAck(消息标识码,是否批量接收消息)。
消费端ACK和重回队列
重回队列:消费端没成功处理的消息,把消息重新发回broker。消息在队列尾部。
channel.basicNack(envelope.getDeliveryTag(),false,false);回执消息发送失败,第三个参数为是否重回队列。
TTL队列/消息
Time To Live的缩写,也就是生存时间。
RabbitMQ支持消息的过期时间,在消息发送时可以进行指定。还支持队列内消息的过期时间,从消息入队列开始计算,只要超过了队列的超时时间配置,那么消息会自动的清除。
死信队列
DLX,Dead-Letter-Exchange
跟交换器和队列息息相关。
利用DLX,当消息在一个队列中变成死信队列(dead message)之后,它能被重新publish到另一个exchange,这个exchange就是DLX。消息没有消费者消费。
变为私信的情况:消息被拒绝,就是被nack。TTL过期,消息过期了。队列达到最大程度后,消息会送到死信队列。
DLX也是一个正常的Exchange,和一般的Exchange没有区别,它能在任何队列上被指定,实际上就是设置某个队列的属性。当队列中有死信时,rabbitmq就会自动将这个消息重新发布到设置的exchange上去,进而被路由到另一个队列。
设置死信队列
首先需要设置死信队列的enchange和queue,然后进行绑定,路由key设置为#。
正常什么交换机、队列、绑定,只不过我们需要在队列加上一个参数即可:arguments.put(“x-dead-letter-exchange”,”dlx.exchange”)。
这样消息在过期、requeue(拒绝接受)、队列达到最大程度,消息就可以直接路由到死信队列。
Rabbitmq整合spring AMQP
Rabbitadmin
管控组件。可以很好的操作rabbitmq,在spring中直接注入。
AutoStartup必须要设置为true,否则spring容器不会加载rabbitadmin类
Rabbitadmin底层实现就是从spring容器中获取exchange、bingding、routingkey以及queue的@Bean声明。
使用rabbittemplate的excute方法执行对应的声明、修改、删除等一系列rabbitmq基础功能操作。
SpringAMPQ声明
声明式创建队列和交换机。
Rabbittemplate
消息模板。
与springamqp整合的时候进行发送消息的关键类。
提供了丰富的发送消息方法,包括可靠性投递消息方法、回调监听消息接口confirmcallback、返回值确认接口returncallback等等。同样我们需要注入spring容器。
SimpleMessageListenContainer
简单消息监听容器。
监听队列(多个)、自动启动、自动声明。
设置事务特性、事务管理器、事务属性、事务容量(并发)、是否开启事务、回滚消息等。
设置消费者数量、最大最小数量、批量消费。、
设置消息签收模是否重回队列、异常捕获handler函数。
设置消费者标签生成策略、是否独占模式、消费者属性等。
设置具体监听器、消息转换器等。
可以进行动态设置,比如在运行中的应用可以动态的修改其消费者数量的大小、接收消息的模式等。
MessageListenerAdapter
消息监听适配器。
核心属性:defaultListenerMethod默认监听方法名称:用于设置监听方法名称。
Delegate委托对象:实际真实的委托对象,用于处理消息。
QueueOrTagMethodName队列标识与方法名称组成的集合。
MessageConverter
消息转换器。序列化和反序列化。
自定义转换器一般实现MessageConverter接口,重写toMessage(java对象转成message对象)和fromMessage(message对象转成java对象)方法。
Rabbitmq整合springboot
Publisher-confirms,实现一个监听器用于监听broker端给我吗返回的确认请求rabbitTemplate.ConfirmCallback
Publisher-returns,保证消息对broker端是可达的,如果出现路由键不可达的情况,则使用监听器对不可达的消息进行后续的处理,保证消息的路由成功:RabbitTemplate.ReturnCallback.。
消费端监听使用@RabbitListener注解。
RabbitListener是一个组合注解,里面可以配置@QueueBinding、@Queue、@Ecxchange直接通过这个组合注解一次性搞的消费端交换机、队列、绑定、路由、并且配置监听功能等。
@RabbitHandler消费者监听方法,。监听队列消息自动接收并处理。
ignoreDeclarationExceptions为忽略声明异常。
Springcloud stream整合
Barista接口:barista接口是定义来作为后面类的参数,这一接口定义来通道类型和通道名称,通道名称是作为配置用,通道类型则决定了app会使用这一通道进行发送消息还是从中接收消息。
@output:输出注解,用于定义发送消息接口。作用于接口
@input:输入注解,用于定义消息的消费者接口。作用于接口
@StreamListener:用于定义监听方法的注解。