备份交换器
备份交换器,英文名称为 Altemate Exchange,简称庙,或者更直白地称之为"备胎交换器"。 生产者在发送消息的时候如果不设置 mandatory 参数, 那么消息在未被路由的情况下将会丢失: 如果设置了 mandatory 参数,那么需要添加 ReturnListener 的编程逻辑,生产者的代码将变得复杂。如果既不想复杂化生产者的编程逻辑,又不想消息丢失,那么可以使用备份交换器, 这样可以将未被路由的消息存储在 RabbitMQ 中,再在需要的时候去处理这些消息。
代码如下:
1 channel.ExchangeDeclare("myAe", "fanout", true, false, null); //声明备份交换器 2 Dictionary<string, object> arg = new Dictionary<string, object>(); 3 arg.Add("a1ternate-exchange", "myAe"); 4 channel.ExchangeDeclare("ExchangeName", "direct", true, false, arg); //声明交换器与备份交换器绑定 5 channel.QueueDeclare("QueueName", true, false, false, null); 6 channel.QueueDeclare("QueueAe", true, false, false, null); //备份队列 7 channel.QueueBind("QueueName", "ExchangeName", "RoutingKey", null); 8 channel.QueueBind("QueueAe", "myAe", ""); 9 channel.BasicPublish("ExchangeName", "RoutingKey",null, Encoding.UTF8.GetBytes("helloword"));
当消息的 RoutingKey 不是 “RoutingKey”时,消息将不能被正确路由到“ExchangeName”上的队列,此时就会发送给 myAe 交换器,进而发送到 QueueAe这个队列 。
考虑到备份交换器的作用,建议将交换器类型设置为fanout,因为消息被重新发送到 备份交换器时的路由键和从生产者发出的路由键是一样的。
过期时间(TTL)
RabbitMQ 可以对"消息"和"队列"设置 TTL。
目前有两种方法可以设置消息的 TTL。第一种方法是通过队列属性设置,队列中所有消息都有相同的过期时间。第二种方法是对消息本身进行单独设置,每条消息的TTL可以不同。如果两种方法一起使用,则消息的 TTL 以两者之间较小的那个数值为准。消息在队列中的生存时间一旦超过设置的 TTL 值时,就会变成"死信" (Dead Message),消费者将无法再收到该消息。
1 channel.ExchangeDeclare("ExchangeName", "direct", true, false, null); //声明交换器与备份交换器绑定 2 Dictionary<string, object> arg = new Dictionary<string, object>(); 3 arg.Add("x-message-ttl", 5000); //设置队列过期时间 5000ms 4 channel.QueueDeclare("QueueName", true, false, false, arg); 5 channel.QueueBind("QueueName", "ExchangeName", "RoutingKey", null); 6 var basicProperties = channel.CreateBasicProperties(); 7 basicProperties.Expiration = "4000"; //设置消息过期时间 4000ms 8 channel.BasicPublish("ExchangeName", "RoutingKey", basicProperties, Encoding.UTF8.GetBytes("helloword"));
对于第一种设置队列 TTL 属性的方法,一旦消息过期,就会从队列中抹去,而在第二种方 法中,即使消息过期,也不会马上从队列中抹去,因为每条消息是否过期是在即将投递到消费者之前判定的。
死信队列
DLX,全称为 Dead-Letter-Exchange,可以称之为死信交换器,也有人称之为死信邮箱。当消息在一个队列中变成死信 (dead message) 之后,它能被重新被发送到另一个交换器中,这个交换器就是 DLX,绑定 DLX 的队列就称之为死信队列。
消息变成死信一般是由于以下几种情况:
- 消息被拒绝 (Basic.Reject/Basic .Nack),井且设置 requeue 参数为 false;
- 消息过期;
- 队列达到最大长度。
DLX 也是一个正常的交换器,和一般的交换器没有区别,它能在任何的队列上被指定, 实 际上就是设置某个队列的属性。当这个队列中存在死信时 , RabbitMQ 就会自动地将这个消息重新发布到设置的 DLX 上去,进而被路由到另一个队列,即死信队列。可以监听这个队列中的消息,以进行相应的处理。
1 channel.ExchangeDeclare("exchange.dlx", "direct", true); //声明DLX 2 channel.ExchangeDeclare("ExchangeName", "direct", true); //声明交换器与备份交换器绑定 3 Dictionary<string, object> arg = new Dictionary<string, object>(); 4 arg.Add("x-dead-letter-exchange", "exchange.dlx"); //设置DLX 5 arg.Add("x-dead-letter-routing-key", "routingkey"); //为私信消息重设路由键 6 channel.QueueDeclare("QueueName", true, false, false, arg); 7 channel.QueueDeclare("DlQueue",true,false,false); 8 channel.QueueBind("QueueName", "ExchangeName", "RoutingKey", null); 9 channel.QueueBind("DlQueue", "exchange.dlx", "routingkey"); 10 var basicProperties = channel.CreateBasicProperties(); 11 basicProperties.Expiration = "4000"; //设置消息过期时间 4000ms 12 channel.BasicPublish("ExchangeName", "RoutingKey", basicProperties, Encoding.UTF8.GetBytes("helloword"));
如果4s内消息没有被消费者消费,那么判定这条消息为过期,消息就会被丢给exchange.dlx,进而转发给DlQueue。
死信队列
延迟队列存储的对象是对应的延迟消息,所谓"延迟消息"是指当消息被发送以后,并不想让消费者立刻拿到消息,而是等待特定时间后,消费者才能拿到这个消息进行消费。
延迟队列可以通过设置消息的ttl和死信队列来实现,消费者订阅死信队列达到延迟效果。
过期时间(TTL)