RabbitMQ高级特性
RabbitMQ高级特性及分布式事务
RabbitMQ之TTL
TTL: 过期时间TTL表示可以对消息 设置预期时间,在这个期间消息可以被消费者消费,过了之后消息将被自动删除,RabbitMQ可以对消息和队列设置TTL,目前可以有俩种方式进行设置。一旦过了预期时间,消息可以俩种方式处理,一种是直接删除,另一种将过期的消息存放在死信队列中,关于死信队列后续会有说明。
TTL设置的方式
方式一: 过期时间为我们的队列参数设置,那么该队列中所有消息都享有同样的过期时间;
当声明设置了TTL的队列时在RabbitMQ WEB端会有对应的标识如下:
代码片段:
/**
* 声明队列1,并设置队列的过期时间
*/
@Bean
public Queue ttlQueue(){
Map<String,Object> map = new HashMap<>();
map.put("x-message-ttl",5000);//队列过期时间/毫秒
return new Queue("springboot-ttl-queue",true,false,false,map);
}
方式二: 过期时间对某条消息单独的设置,每条消息的TTL可以根据业务不同而设置不一样的TTL。
附:当队列和消息同时设置了过期时间,那么以最小的过期时间为准
倆者区别:
过期队列的消息过期之后可以写入到死信队列,而过期消息过期之后就是过期了,不会写入到死信队列中。
RabbitMQ之死信队列
概述
**DLX:**全称为dead-letter-exchange,又称之为死信交换机 ,也称之为死信邮箱,当消息在一个队列中变成死信(dead-message)之后,它能被重新发送到另一个交换机,这个交换机就是DLX,绑定DLX的队列称之为死信队列。
消息死信(dead-message)产生的原因:
- 消息被拒绝
- 消息过期
- 队列达到最大长度
DLX工作原理
DLX也是一个正常交换机,和一般的交换机没有区别,它可以在任何队列上指定,即如同给队列设置TTL一样,以参数的形式进行绑定,当这个队列中存在死信的时候,RabbitMQ会自动将这个消息重新发布到设置的DLX交换机上,同时被路由到对应的死信队列中去,是一种可靠消费的机制,容错,死信队列和死信交换机和一般的交换机和普通队列没什么区别,只是用来作为备胎或者容错记录备份而已。
web界面使用截图
由上图可知,该队列已经设置对应的队列过期时间、队列的最大长度、同时指定了对应的死信队列及死信交换机。
查看对应的队列的overview可以看见详细参数配置:
代码配置
<!--在指定的队列配置中加入相关死信绑定参数配置如下: -->
/**
* 声明过期队列,并设置队列的过期时间
* 死信产生的原因
* 1、队列过期
* 2、队列达到最大长度
* 3、消息被拒绝
* 此示例只测试死信产生原因的1、2的原因
*/
@Bean
public Queue ttlQueue(){
Map<String,Object> map = new HashMap<>();
map.put("x-message-ttl",5000);//队列过期时间/毫秒,若是超过5s,则也会进入DLX中
map.put("x-max-length",5);//配置该队列的最大长度,若是超过则就会进入指定的DLX中
//为过期队列设置死信交换机、死信路由
map.put("x-dead-letter-exchange","springboot-dead-exchange");
map.put("x-dead-letter-routing-key","dead");
return new Queue("springboot-ttl-queue",true,false,false,map);
}
<!--死信交换机及队列配置类 -->
/**
* 配置死信交换机及队列用来作为死信队列的容错
*/
@Configuration
public class DeadLXRabbitMqConfiguration {
public static final String exchangeName="springboot-dead-exchange";
/**
* 声明死信交换机
*/
@Bean
public DirectExchange deadDirectExchange(){
return new DirectExchange(exchangeName,true,false);
}
/**
* 声明死信队列,和一般的队列没有什么区别
*/
@Bean
public Queue deadQueue(){
return new Queue("springboot-dead-queue",true);
}
/**
* 绑定交换机和死信队列
*/
@Bean
public Binding deadBinding(){
return BindingBuilder.bind(deadQueue()).to(deadDirectExchange()).with("dead");
}
注意:若在后端修改已经存在的队列参数时,队列不会进行更新,只有删除队列重新声明或者在全部重新定义一个即可。
RabbitMQ内存磁盘的监控
消息持久化:指消息先存放在内存中,然后持久化到磁盘中,默认内存是总内存的0.4,若超过这个大小,所有的channel信道都会报黄/红,这样生产者投递的消息就会被阻塞blocking,不再接收消息。
配置RabbitMQ监控
RabbitMQ配置请参考:https://www.rabbitmq.com/configure.html
我们可以通过命令的方式也可以通过配置文件rabbitmq.conf的方式进行配置
RabbitMQ内存预警
命令方式:
#通过设置相对内存
rabbitmqctl set_vm_memory_high_watermark 0.4
#通过设置绝对大小内存
rabbitmqctl set_vm_memory_high_watermark absolute 2GB
配置文件方式:
cd /etc/rabbitmq/rabbitmq.conf
#使用相对值 配置时,阈值建议在0.4-0.7之间,最好不要超过0.7
vm_memory_high_watermark.relative = 0.6
# 使用绝对值时,后面要根据具体的设定给出是KB 、MB还是GB
vm_memory_high_watermark.absolute = 2GB
fraction/value 为内存阈值,默认情况是0.4/2GB,代表的含义是当RabbitMQ的内存超过40%的时候,就会产生警告,并且阻塞所有连接的生产者的信息,通过此命令修改阈值会在broker重启之后失效,通过修改配置文件的方式修改阈值则不会,但是修改完配置文件也要重启服务。
RabbitMQ磁盘预警及配置
当磁盘的剩余空间低于确定的阈值时,RabbitMQ同样会阻塞生产者,这样可以避免因非持久化的消息持续换页而导致耗尽磁盘空间进而导致服务器崩溃。
默认情况下:磁盘预警为50MB时就会进行预警。表示当前磁盘空间为50MB时就会阻塞生产者并且停止内存消息换页到磁盘的过程;
这个阈值可以减小,但是不能完全消除因磁盘空间耗尽而导致的服务器崩溃的问题,比如在俩次磁盘检查空隙内,第一次磁盘检查是60MB,第二次检查是1MB则就会出现报警。
磁盘主要是预警是下限,比如我设置了100GB,那么如果我现在的磁盘大小小于这个阈值就会报警,而内存是大于这个对应的阈值就会报警
命令方式:
#通过设置相对内存 disk_limit 固定单位是KB 、MB、GB
rabbitmqctl set_dist_free_limit <disk_limit>
#通过设置绝对大小内存fraction 是相对于内存的阈值,建议在1.0~2.0之间
rabbitmqctl set_dist_free_limit memory_limit <fraction>
配置文件方式:
cd /etc/rabbitmq/rabbitmq.conf
#使用相对值 配置时,阈值建议在0.4-0.7之间,最好不要超过0.7
dist_free_limit.relative = 3.0
# 使用绝对值时,后面要根据具体的设定给出是KB 、MB还是GB
dist_free_limit.absolute = 2GB
RabbitMQ的内存换页
在某个Broker节点及内存阻塞生产者之前,他会尝试将内存中的资源换页到磁盘中,以释放内存空间,持久化和非持久化的消息都会写入磁盘中,其中持久化的消息本身就在磁盘中有一个副本,所以转移过程中,持久化的消息首先会在内存中进行清除。
默认情况下,内存达到阈值的50%就会进行换页处理。
也就是说,默认阈值是内存的0.4,那么就会在0.4*0.5=0.2的时候就会进行换页处理。
例如:有1000MB的内存, 当内存使用率达到400MB的时候就已经处于阈值状态,那么在达到400MB之前,在达到200MB时候就会进行换页处理,从而释放内存。
配置内存换页
cd /etc/rabbitmq/rabbitmq.conf
#使用相对值 配置时,阈值建议在0.4-0.7之间,最好不要超过0.7
vm_memory_high_watermark.relative = 0.4
# 设置换页阈值配置,默认0.5 为什么设置为小于1,因为如果设置为1就相当于等于阈值,这样内存都已经到了极限了,再去换页就没有意义了。
vm_memory_high_watermark_paging_ratio = 0.7