系列目录
RabbitMQ 入门系列:1、MQ的应用场景的选择与RabbitMQ安装。
RabbitMQ 入门系列:2、基础含义:链接、通道、队列、交换机。
RabbitMQ 入门系列:3、基础含义:持久化、排它性、自动删除、强制性、路由键。
RabbitMQ 入门系列:4、基础编码:官方SDK使用:链接创建、单例改造、发送消息、接收消息。
RabbitMQ 入门系列:5、基础编码:交换机的进阶介绍及编码方式。
RabbitMQ 入门系列:6、保障消息:不丢失:发送方、Rabbit存储端、接收方。
RabbitMQ 入门系列:7、保障消息:不重复消费:产生消息的唯一ID。
RabbitMQ 入门系列:8、扩展内容:接收信息时:可否根据RoutingKey过滤监听信息,答案是不能。
前言:
延迟队列用于事件发生后间隔一段时间后需要做特定处理的场景,如:
1、电商支付系统中,用户下单后N分钟不支付,自动取消订单。
2、用户浏览商品长时间后还没下单,后续推送相关产品和优惠券。
3、用户注册或修改生日后:生日短信推送等。
4、7天后的自动确认收货等。。。
......
对于这类应用,用消息队列,对个别可能是合适的,但对整个系统应用而言,它是不靠谱的。
消息队列的核心应用,是保持内存的队列,不断的产生并不断的消耗,最佳状态的保持系统的稳定和流畅。
而延迟队列的核心,是积压消息,大量积压消息,这明显与消息队列的设计就不符合。
下面来看看网传用死信队列来实现延迟队列的方式
1、死信队列的概念:
1、默认队列的消息过期了,或是被拒约处理,系统就是直接丢弃掉的。
2、如果你不希望过期的消息,被系统直接丢弃,还想拿来二次处理,那么:
可以通过绑定另一个队列,并标识为“x-dead-letter-exchange”,
那么,原本要丢弃的消息,就都转发到这指定的队列中,这个接收丢弃信息的队列,就叫死信队列。
2、死信队列的编码:
using (var channel = Rabbit.Instance.DefaultConnection.CreateModel())
{
//定义普通队列来接收丢弃的信息
channel.QueueDeclare("dead");
IDictionary<string, object> dic2 = new Dictionary<string, object>();
dic2.Add("x-dead-letter-exchange", "");//使用默认交换机
dic2.Add("x-dead-letter-routing-key", "dead");//设置转移到的队列
dic2.Add("x-message-ttl", 6000);//设置过期时间
channel.QueueDeclare("sendtodead", arguments: dic2);
channel.BasicPublish("", "sendtodead", false, null, Encoding.UTF8.GetBytes("6秒就过期了1。"));
channel.BasicPublish("", "sendtodead", false, null, Encoding.UTF8.GetBytes("6秒就过期了2。"));
}
运行后,消息从sendtoddead队列6秒过期后,转移到dead队列。
3、死信队列它的适用场景:
1、队列有统一的过期时间,不能使用单个信息的过期时间:
因为MQ不扫整个队列,只扫描队列第1个,判断是否过期,因此要求先进队列的必须先过期。
2、过期时间应该较短(根据可能积压的数据考量时间,一个核心的考量数据量是:10万条-100万条),避免长时间积压数据
对于长时间不消费的,不应该存入MQ,毕竟MQ的核心是内存队列,而不是磁盘队列。
4、死信队列它为什么不适合当延时队列:
了解完死信队列,会发现,其实在一个系统中,仅有比如N分钟后要处理逻辑的场景,比较适合,
其它N天后要处理的,都不靠谱。
而你用了N分钟的场景,那其它场景你用不用?
用了,不靠谱!
不用,得用其它方案,方案会不会多样化,不方便管理?
总结:
1、如果非要用死信队列当延时队列,那么要建立很多个第N分钟过期的队列。
2、如果非要用死信队列当延时队列,那么下一篇介绍的官方的延时队列插件,会比死信队列更合适。