二、RabbitMQ 进阶特性及使用场景 [.NET]
前言
经过上一篇的介绍,相信大家对RabbitMQ 的各种概念有了一定的了解,及如何使用RabbitMQ.Client 去发送和消费消息。
特性及使用场景
1. TTL 过期时间
TTL可以用来指定queue 和message多久会被去掉;在短期message数量很大,或者订单需要特定失效(例如15min支付)等场景,设置消息的过期时间可以减轻rabbitmq的压力,后者可以帮助方便的实现业务。
那么如何设置消息过期时间呢?
- 为queue中的消息整体设置
var ttlSetting = new Dictionary<string, Object>(); ttlSetting.Add("x-message-ttl", 10000); queueName = _channel.QueueDeclare(arguments: ttlSetting).QueueName;
- 为每条message设置过期时间
var properties = _channel.CreateBasicProperties(); properties.Expiration = "10000"; var messageBytes = ObjectToByteArray(message); _channel.BasicPublish(TicketExchangeName, optType, false, properties, messageBytes);
队列TTL 设置
我们不但可以对message 设置过期时间,还可以对消息队列设置生存时间,当超过设定时间未被使用,该消息队列可以被自动删除。
设置方法同样是在声明队列的时候传入参数即可:
var ttlSetting = new Dictionary<string, Object>(); ttlSetting.Add("x-expires", 6000); queueName = _channel.QueueDeclare(arguments: ttlSetting).QueueName;
2. 死信交换器和死信队列
何为死信?
- 被拒绝的消息
- 过期的消息
- 消息队列达到最大长度
当死信发生时,死信会通过死信交换机进入到声明的死信队列,可以通过参数声明:
_channel.ExchangeDeclare(DLExchangeName, ExchangeType.Direct); var arguments = new Dictionary<string, Object>(); arguments.Add("x-dead-letter-exchange", DLExchangeName); _channel.QueueDeclare("dlqueue", arguments: arguments);
死信消息的路由,如果在消息初始被投送到的队列上设置了 x-dead-letter-routing-key 参数,则死信消息路由时以这个为准,否则按照它被产生时的路由key为准。
例如,如果您将消息发布到具有路由密钥 foo 的交换,并且该消息是死信的,它将被发布到其具有路由密钥 foo 的死信交换。如果消息最初登陆的队列已声明为 x-dead-letter-routing-key 设置为 bar,则消息将发布到其带有路由键 bar 的死信交换。
查看死信队列中的消息可以帮助我们了解分析程序的运行健康情况,明确异常发生的原因。
3. 交换机,队列,消息的持久化
交换机的持久化是我们在使用rabbitmq经常需要做的事情,声明交换器时将 durable 参数设置为 true 来实现的。如果不设置持久化属性的话,当 RabbitMQ 服务重启后交换器的数据就会丢失,需要注意的是,是交换器的数据丢失,消息不会丢失,只是不能将消息发送到这个交换器中了,一般生产环境使用都会把该属性设置为持久化。
队列的持久化:先介绍队列的持久化,是因为消息的持久化是依赖在队列持久化之上的。通过在声明时将durable 参数设置为 true 达到目的。
_channel.QueueDeclare(“myqueue”, true, false, arguments: ttlSetting)
消息的持久化:通过在publish 消息时,设置基本属性 DeliveryMode 来实现消息的持久性。
var properties = _channel.CreateBasicProperties(); properties.DeliveryMode = 2;
4. 消息的确认机制
相比于http请求和RPC,message queue的应用确实带来了不少便利,但引入新的application不可避免的增加了可靠性的考虑;如何确保消息从生产者准确的投递到了rabbitmq broker,又如何确保消费者真的消费了消息,又或者消费者没有重复消费消息?
这些都是我们在使用消息队列时候要考虑的问题,如何你使用何种技术(RabbitMQ或者是Kafka)。
其中,在保证消息的准确投递和消费上,RabbitMQ提供了确认机制帮助我们确保消息的可靠性。
生产端的消息确认机制:
消息确认的处理办法分为:单个消息同步确认(吞吐量低),批量消息同步确认,消息异步确认。这里只介绍异步confirm的情况。
var channel = connection.CreateModel(); channel.ConfirmSelect(); channel.BasicAcks += (sender, ea) => { // code when message is confirmed }; channel.BasicNacks += (sender, ea) => { //code when message is nack-ed };
var outstandingConfirms = new ConcurrentDictionary<ulong, string>();
如果希望在投递失败后,重新投递,可以用 ConcurrentDictionary 存储deliverTag 和 消息体,在投递失败后,重新投递。
消费端的消息确认机制:
1. 自动应答
消费者在消费消息的时候,如果设定应答模式为自动,则消费者收到消息后,消息就会立即被 RabbitMQ 从 队列中删除掉。
因此,在实际开发者,我们基本上是将消费应答模式设置为手动确认更为妥当一些。
_channel.BasicConsume(queue: queueName, autoAck: true, consumer: consumer);
2. 手动应答
消费者在收到消息后:
- 可以在既定的正常情况下进行确认(告诉 RabbitMQ,我已经消费过该消息了,你可以删除该条数据了);
- 可以在既定的异常情况下不进行确认(RabbitMQ 会继续保留该条数据),这样下一次可以继续消费该条数据。
_channel.BasicAck(ea.DeliveryTag, false);
本文介绍了过期时间,死信队列,应答机制和持久化的设置和使用场景,后续还会继续介绍RabbitMQ的其它特性和集群搭建,欢迎大家关注和提出意见。
---------------------------------------------------
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)