一、消息可靠投递
生产端的
在使用 RabbitMQ的时候,作为消息发送方希望杜绝任何消息丢失或者投递失败场景。
RabbitMQ 为我们提供了两种方式用来控制消息的投递可靠性模式。
- confirm 确认模式
- return 退回模式
rabbitmq整个消息投递的路径为:
producer--->rabbitmq broker--->exchange--->queue--->consumer
- 消从 producer到exchange 则会返回一个confirmCallback
- 消息从 exchange-->queue 投递失败则会返回一个returnCallback
我们将利用这两个callback 控制消息的可靠性投递
confirmCallback
returnCallback
二、Consumer Ack
消费端的
ack指acknowledge,确认。表示消费者接收到消息后的确认方式
三种:
- 自动确认: acknowledge="none
- 手动确认:acknowledge="manual
- 根据异常情况确认:acknowledge="auto"(这种方式使用麻烦,不作讲解)
自动确认是指,当消息一旦被Consumer接收到,则自动确认收到,并将相应 mesage 从 RabbitMQ的消息缓存中移除。但是在实际业务处理中,很可能消息接收到,业务处理出现异常,那么该消息就会丢失。
如果设置了手动确认方式,则需要在业务处理成功后,调用channel.basicAck0,手动签收,如果出现异常,则调用channel.basicNack0方法,让其自动重新发送消息。
1、自动确认
什么都不配置默认就是自动确认
2、手动确认
实现的不是messagelistener而是他的子接口,然后开启手动确认
3、小结
三、限流
这样配置的话就是代表用了手动接收,然后每次只接收一条消息,手动确认之后才有下一条,如果去掉prefetch=“1”,那么一次就会把消息全部拉过来
在<rabbit:listener-container>中配置 prefetch属性设置消费端一次拉去多少消息
消费端的确认模式一定为手动确认,acknowledge="manual"
四、TTL
Time to Live(存活时间/过期时间)
当消息到达存活时间后,还没有被消费,会被自动清除
RabbitMQ可以对消息设置过期时间,也可以对整个队列设置过期时间
1、队列统一过期
配置好队列和交换机,设置好队列的过期时间 10秒
队列过期后,会统一的把全部消息都删除掉
消息过期后,只有消息在队列顶端,才会判断其是否过期然后马上删除,如果不是队列顶端的,只有消息被用到前才会判断是否过期,跟redis的惰性删除很像
2、消息单独过期
写完然后把这个匿名内部类当参数传入covertandsend里面:
如果设置了消息的过期时间,也设置了队列的消息时间,以时间短的为主
3、小结
- 设置队列过期时间使用参数: -message-ttl,单位: ms(毫秒),会对整个队列消息统一过期
- 设置消息过期时间使用参数:expiration。单位:ms(毫秒),当该消息在队列头部时 (消费时),会单独判断这一消息是否过期。
- 如果两者都进行了设置,以时间短的为准
五、死信队列
别的mq没有exchange所有叫死信队列,但rabbitMQ有exchange所以也叫死信交换机
死信队列,DLX。Dead letter Exchange(死信交换机),当消息成为Dead message后,可以被重新发送到另一个交换机,这个交换机交DLX
如果一个消息过期了,没有被正常消费,如果绑定了死信队列,不会被丢弃而是发到死信交换机上重新发送给另一个队列,也可以绑定消费者。
什么消息会变死信(重点)
- 队列消息长度达到限制
- 消费者拒接消费消息,basicNack/basicReject,并且不把消息重新放入原目标队列,requeue=false
- 原队列存在消息过期设置,消息到达超时时间未被消费
队列绑定死信交换机:
给队列设置参数:x-dead-letter-exchange和x-dead-letter-routing-key
第一个参数就是设置死信交换机的名称,第二个参数就是死信队列绑定的routingkey
六、延迟队列
场景:现在要求用户下单之后,如果30分钟未支付,取消订单,回滚库存,支付了就不操作
实现方式:定时任务(不够优雅),延迟队列
RabbitMQ中未提供延迟队列的功能
但是,我们可以通过 TTL+DLX(死信队列)的方式来实现延迟队列的效果
我们可以定义一个队列过期时间为30分钟,绑定个死信交换机,然后没有消费者监听死信队列,不监听正常队列,就等他过期,过期了就会发送到私信交换机,死信交换机再发送给消费者。
七、优先级队列
优先级队列是按照优先级来优先执行,而不是按先进先出的顺序
八、惰性队列
惰性队列:消息保存在磁盘中,正常的队列是把消息存放在内存中
场景:当消费者宕机或者处于维护状态,导致长时间内不能消费而造成堆积的时候,惰性队列就很有必要了。
惰性队列的性能会比较低,占用内存很小。
九、应用问题
1、消息补偿机制
需求:要100%保证消息发送成功
首先生产者先把数据入库然后发送消息到队列1,如果消费者成功接收也入库,消费者接收到还要发送确认消息到队列2。生产者还会延迟发送消息给队列3,队列3和队列2的消息都会被监听到回调检查服务,如果他们的消息是不同的,队列3消息监听到发现2不在里面说明没有发成功,调用producer重新发送。如果发送消息和延迟发送都失败怎么办?还有个定时任务去定时检查回调数据库,看是否有数据没用就调用hseng
2、幂等性的保障
幂等性指的是一次或多次请求某一个资源,对于一个资源本身一个有相同的结果。
既任意多次执行对资源本身所产生的的影响均与一次的影响相同
MQ中:消费多条相同的消息,得到与消费改消息一次相同的结果
比如说我买东西画了500块,但是因为某些原因mq发了两条消息,要保证账户只扣500元
我们发消息的时候版本是1,重复发消息还是会是1多次发送还是1,但是我们只要有一个成功了,我们数据库的版本就会变成2,这样就算第二次1版本过来也和更新完的版本2不一样了失败。保证了幂等性。