过期时间TTL(Time To Live)
过期时间TTL表示可以对消息设置预期的时间,在这个时间内都可以被消费者接收获取;过了之后消息将自动被删除。
目前有两种方法可以设置
- 第一种方法是通过队列属性设置,队列中所有消息都有相同的TTL。
- 第二种方法是对消息进行单独设置,每条消息TTL可以不同。
当同时指定了 queue 和 message 的 TTL 值,则两者中较小的那个才会起作用。
设置队列TTL
-
过期时间参数(x-message-ttl 为固定值)
-
在springboot_rabbitmq_producer 代码的基础上新增以下配置文件
参数 x-message-ttl 的值 必须是非负 32 位整数 (0 <= n <= 2^32-1) ,以毫秒为单位表示 TTL 的值。这样,值 5000 表示存在于 队列 中的当前 消息 将最多只存活 5 秒钟。
package com.cn.config; import org.springframework.amqp.core.Binding; import org.springframework.amqp.core.BindingBuilder; import org.springframework.amqp.core.DirectExchange; import org.springframework.amqp.core.Queue; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.util.HashMap; @Configuration public class TTLDirectRabbitmqConfig { //1.声明交换机 @Bean public DirectExchange ttldirectExchange(){ return new DirectExchange("ttl-direct-exchange", true, false); } //2.声明队列 @Bean public Queue directTTLQueue(){ //设置过期时间,以毫秒为单位 HashMap<String, Object> map = new HashMap<>(); map.put("x-message-ttl", 5000); return new Queue("ttl.direct.queue", true, false, false, map); } //3.交换机和队列进行绑定 @Bean public Binding directTTLBinding(){ return BindingBuilder.bind(directTTLQueue()).to(ttldirectExchange()).with("ttl"); } }
-
生产者代码中新增以下方法
public void createOrderDirectTTL(String useerId, String productId, int num){ String orderId = UUID.randomUUID().toString(); String exchangeName = "ttl-direct-exchange"; String routeKey = "ttl"; rabbitTemplate.convertAndSend(exchangeName, routeKey, orderId); }
-
测试类
@Test void testOrderDirectTTL() { orderService.createOrderDirectTTL("1","1",555); }
-
启动测试,查看图形化管理界面,会看到队列上有DDL标识
静等5秒之后会看到消息自动消失
设置消息TTL
-
在上面代码的基础上修改
@Bean public Queue directTTLQueue2(){ return new Queue("ttl2.direct.queue", true); } @Bean public Binding directTTL2Binding(){ return BindingBuilder.bind(directTTLQueue2()).to(ttldirectExchange()).with("ttl2"); }
-
生产者代码
public void createOrderDirectTTL2(String useerId, String productId, int num){ String orderId = UUID.randomUUID().toString(); String exchangeName = "ttl-direct-exchange"; String routeKey = "ttl2"; // 对消息设置过期时间 MessagePostProcessor messagePostProcessor = new MessagePostProcessor() { @Override public Message postProcessMessage(Message message) throws AmqpException { message.getMessageProperties().setExpiration("5000"); return message; } }; rabbitTemplate.convertAndSend(exchangeName, routeKey, orderId, messagePostProcessor); }
expiration 字段以微秒为单位表示 TTL 值。且与 x-message-ttl 具有相同的约束条件。因为 expiration 字段必须为字符串类型,broker 将只会接受以字符串形式表达的数字。
-
测试代码
@Test void testOrderDirectTTL2() { orderService.createOrderDirectTTL2("1","1",666); }
-
启动测试,查看图形化管理界面,会看到队列上没有DDL标识,但是我们静等5秒钟后,队列中的消息也会自动消失
死信队列
DLX,全称为Dead-Letter-Exchange , 可以称之为死信交换机,也有人称之为死信邮箱。
当消息在一个队列中变成死信(dead message)之后,它能被重新发送到另一个交换机中,这个交换机就是DLX ,绑定DLX的队列就称之为死信队列。
消息变成死信,可能是由于以下的原因:
- 消息被拒绝
- 消息过期
- 队列达到最大长度
DLX也是一个正常的交换机,和一般的交换机没有区别,它能在任何的队列上被指定,实际上就是设置某一个队列的属性。当这个队列中存在死信时,Rabbitmq就会自动地将这个消息重新发布到设置的DLX上去,进而被路由到另一个队列,即死信队列。
要想使用死信队列,只需要在定义队列的时候设置队列参数 x-dead-letter-exchange
指定交换机即可。
-
添加死信队列和交换机绑定关系
package com.cn.config; import org.springframework.amqp.core.Binding; import org.springframework.amqp.core.BindingBuilder; import org.springframework.amqp.core.DirectExchange; import org.springframework.amqp.core.Queue; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * 死信队列 */ @Configuration public class DeadDirectRabbitmqConfig { //1.声明交换机 @Bean public DirectExchange deadDirectExchange(){ return new DirectExchange("dead-direct-exchange", true, false); } //2.声明队列 @Bean public Queue directDeadQueue(){ return new Queue("dead.direct.queue", true); } //3.交换机和队列进行绑定 @Bean public Binding directDeadBinding(){ return BindingBuilder.bind(directDeadQueue()).to(deadDirectExchange()).with("dead"); } }
-
修改TTLDirectRabbitmqConfig配置
//2.声明队列 @Bean public Queue directTTLQueue(){ //设置过期时间 HashMap<String, Object> map = new HashMap<>(); map.put("x-message-ttl", 5000); //过期时间 map.put("x-dead-letter-exchange", "dead-direct-exchange"); //死信队列 map.put("x-dead-letter-routing-key", "dead"); // direct模式需要配置routing-key return new Queue("ttl.direct.queue", true, false, false, map); }
-
启动测试(需要先删除ttl.direct.queue)
-
过期后就会被投递到之前配置的死信队列中
内存磁盘的监控
内存警告
当内存使用超过配置的阈值或者磁盘空间剩余空间对于配置的阈值时,RabbitMQ会暂时阻塞客户端的连接,并且停止接收从客户端发来的消息,以此避免服务器的崩溃,客户端与服务端的心态检测机制也会失效。
内存的最大极限为0.4 假设电脑是4G,那么内存的最大阈值就是1.6G
内存控制
参考帮助文档:https://www.rabbitmq.com/configure.html 当出现警告的时候,可以通过配置去修改和调整
-
命令
//命令设置比例 rabbitmqctl set_vm_memory_high_watermark <fraction> //命令设置大小 rabbitmqctl set_vm_memory_high_watermark absolute 50MB
fraction/value 为内存阈值。默认情况是:0.4/2GB,代表的含义是:当RabbitMQ的内存超过40%时,就会产生警告并且阻塞所有生产者的连接。通过此命令修改阈值在Broker重启以后将会失效,通过修改配置文件方式设置的阈值则不会随着重启而消失,但修改了配置文件一样要重启broker才会生效。
-
测试案例
[root@hecs-66166 ~]# rabbitmqctl set_vm_memory_high_watermark absolute 50MB Setting memory threshold on rabbit@hecs-66166 to 50MB bytes ...
[root@hecs-66166 ~]# rabbitmqctl set_vm_memory_high_watermark 0.4 Setting memory threshold on rabbit@hecs-66166 to 0.4 ...
内存换页
在某个Broker节点及内存阻塞生产者之前,它会尝试将队列中的消息换页到磁盘以释放内存空间,持久化和非持久化的消息都会写入磁盘中,其中持久化的消息本身就在磁盘中有一个副本,所以在转移的过程中持久化的消息会先从内存中清除掉。
默认情况下,内存到达的阈值是50%时就会换页处理。
也就是说,在默认情况下该内存的阈值是0.4的情况下,当内存超过0.4*0.5=0.2时,会进行换页动作。
比如有1000MB内存,当内存的使用率达到了400MB,已经达到了极限,但是因为配置的换页内存0.5,这个时候会在达到极限400mb之前,会把内存中的200MB进行转移到磁盘中。从而达到稳健的运行。
-
可以通过设置
vm_memory_high_watermark_paging_ratio
来进行调整vm_memory_high_watermark.relative = 0.4vm_memory_high_watermark_paging_ratio = 0.7(设置小于1的值)
为什么设置小于1,以为你如果你设置为1的阈值。内存都已经达到了极限了。你在去换页意义不是很大了。
磁盘预警
当磁盘的剩余空间低于确定的阈值时,RabbitMQ同样会阻塞生产者,这样可以避免因非持久化的消息持续换页而耗尽磁盘空间导致服务器崩溃。
默认情况下:磁盘预警为50MB的时候会进行预警。表示当前磁盘空间第50MB的时候会阻塞生产者并且停止内存消息换页到磁盘的过程。
这个阈值可以减小,但是不能完全的消除因磁盘耗尽而导致崩溃的可能性。比如在两次磁盘空间的检查空隙内,第一次检查是:60MB ,第二检查可能就是1MB,就会出现警告。
-
命令
rabbitmqctl set_disk_free_limit <disk_limit> rabbitmqctl set_disk_free_limit memory_limit <fraction> disk_limit:固定单位 KB MB GB fraction :是相对阈值,建议范围在:1.0~2.0之间。(相对于内存)
-
测试案例
[root@hecs-66166 ~]# rabbitmqctl set_disk_free_limit 40GB Setting disk free limit on rabbit@hecs-66166 to 40GB bytes ...
[root@hecs-66166 ~]# rabbitmqctl set_disk_free_limit 50MB Setting disk free limit on rabbit@hecs-66166 to 50MB bytes ...