业务分析
RabbitMQ消息通常情况很少丢失,但若存在网络波动、服务宕机、程序异常等情况,也会导致消息丢失的情况发生,为了保证我们的系统高可用,必须作出更完善的措施,来保证系统的稳定性。
解决方案
1.消息持久化
RabbitMQ消息默认是存放在内存上面的,如果不进行设置,消息不会持久化到硬盘上面,如果服务重启或者宕机,消息就会丢失。
所以首先要对消息进行持久化,持久化须满足以下三个条件:
- Exchange 设置持久化
- Queue 设置持久化
- Message持久化发送
2.生产者确认机制
发送消息时将信道设置为 confirm 模式,消息进入该信道后,都会被指派给一个唯一ID,一旦消息被投递到所匹配的队列后,RabbitMQ 就会发送给生产者一个确认。
3.消费者手动确认
当消费者消费消息时,未消费完毕就出现了异常,导致消息丢失,所以这时就需要关闭自动确认,改为手动确认消息。
4.死信队列
死信是RabbitMQ中的一种消息机制,当你在消费消息时,如果队列里的消息出现以下情况:
- 消息被否定确认,使用 channel.basicNack 或 channel.basicReject ,并且此时requeue 属性被设置为false
- 消息在队列的存活时间超过设置的TTL时间
- 消息队列的消息数量已经超过最大队列长度
那么该消息将成为死信,如果配置了死信队列,那么该消息将会被丢进死信队列中,如果没有配置,则该消息将会被丢弃。
死信队列不是特殊的队列,只是绑定在死信交换机上的队列。死信交换机也不是特殊的交换机,只是用来接受死信的交换机,所以可以为任何类型。一般来说,会为每个业务队列分配一个独有的路由key,并对应的配置一个死信队列进行监听,也就是说,一般会为每个重要的业务队列配置一个死信队列。
5.消息补偿机制
如果消息确认失败后,我们可以进行消息补偿,也就是消息的重试机制。当未收到确认信息时进行消息的重新投递。达到最大重试次数,可发送邮件预警。
业务实现
1.添加RabbitMQ属性配置及jar包依赖
#RabbitMQ配置
spring.rabbitmq.host=127.0.0.1
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
spring.rabbitmq.virtual-host=/
#消费者数量
spring.rabbitmq.listener.simple.concurrency=10
#最大消费者数量
spring.rabbitmq.listener.simple.max-concurrency=10
#消费者每次从队列获取的消息数量。写多了,如果长时间得不到消费,数据就一直得不到处理
spring.rabbitmq.listener.simple.prefetch=1
#消费者自动启动
spring.rabbitmq.listener.simple.auto-startup=true
#消费者消费失败,自动重新入队,默认是true(与参数acknowledge-mode有关系,为manual手动模式时该属性不生效)
spring.rabbitmq.listener.simple.default-requeue-rejected=false
#启用发送重试
spring.rabbitmq.listener.simple.retry.enabled=true
#1秒钟后重试一次
spring.rabbitmq.listener.simple.retry.initial-interval=1000
#最大重试次数 3次
spring.rabbitmq.listener.simple.retry.max-attempts=3
#最大间隔 10s
spring.rabbitmq.listener.simple.retry.max-interval=10000
#等待间隔 的倍数。如果为2 第一次 乘以2 等1秒, 第二次 乘以2 等2秒 ,第三次 乘以2 等4秒
spring.rabbitmq.listener.simple.retry.multiplier=1
#发送者开启confirm确认机制
spring.rabbitmq.publisher-confirms=true
#发送者开启return确认机制
spring.rabbitmq.publisher-returns=true
#消息确认机制 --- 自动auto 手动manual
spring.rabbitmq.listener.simple.acknowledge-mode=manual
<!--rabbitmq-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
2.创建RabbitMQ配置类
import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;
@Configuration
public class MQConfig {
//Direct模式
public static final String QUEUE="customerQueueTest";
//Topic模式
public static final String TOPIC_QUEUE1="topic.queue1";
public static final String TOPIC_QUEUE2="topic.queue2";
public static f