【RabbitMQ.Clinet笔记】队列(Queue)

Queue参数

  • durable:是否持久化, 队列默认是存放到内存中的,rabbitmq重启会丢失,如果想重启之后还存在就要使队列持久化,保存到Erlang自带的Mnesia数据库中,当rabbitmq重启之后会读取该数据库
  • exclusive:是否排外的,队列在当前connection下的channel中是共享的,其他connection下的channel访问不到,当connection关闭时队列删除。
    一旦该队列被声明,其他连接无法声明相同名称的排他队列。
    队列即使显示声明为durable,连接断开时(注意不是信道断开)也会被自动删除。
    使用场景:系统内部跨进程调用,生产者与消费者在同一系统内。
  • autoDelete:是否自动删除,当最后一个消费者断开连接之后队列是否自动被删除,可以通过RabbitMQ Management查看某个队列的消费者数量,当consumers = 0时队列就会自动删除
  • Arguments:队列其他参数,Dictionary类型
    • x-message-ttl 消息过期时间,message在队列的最大存活时间,单位毫秒。设置后队列Features属性显示TTL。也可以对消息本身设置过期时间
    • x-expires 设置队列的过期时间,如启动一个生产者或启动一个消费者,消费者运行结束后10秒,队列会被删除
    • x-max-length 队列最大长度
    • x-max-length-bytes 指定队列最大内存
    • x-dead-letter-exchange 指定死信交换机
    • x-dead-letter-routing-key 指定死信routingKey
    • x-max-priority 设置优先级,优先级高的先发送consumer
    • x-queue-mode 可以是defaultlazy(惰性队列)。下面对lazy队列有详细说明
    • x-overflow queue的溢出行为,值包括:drop-head(删除queue头部的消息)、reject-publish(最近发来的消息将被丢弃)、reject-publish-dlx(拒绝发送消息到死信交换器)

控制台(RabbitMQ Management)队列属性

  • Features:
    • D:持久化
    • TTL:设置了消息过期时间
    • DLXDLK:表示设置给队列设置了死信交换机和死信消息的routing key
  • Ready:消息的状态,等待投递的消息
  • Unacked:消息的状态,已投递给消费者,但是还没收到消费者确认信号的消息。如果RabbitMQ一直没有收到消费者的确认信号,并且消费此消息的消费者已经断开连接,则RabbitMQ会安排该消息重新进入队列,等待投递给下一个消费者

惰性队列

默认情况下,当生产者将消息发送到RabbitMQ的时候,队列中的消息会尽可能地存储在内存之中,这样可以更加快速地将消息发送给消费者。即使是持久化的消息,在被写入磁盘的同时也会在内存中驻留一份备份。当RabbitMQ需要释放内存的时候,会将内存中的消息换页至磁盘中,这个操作会耗费较长的时间,也会阻塞队列的操作,进而无法接收新的消息。虽然RabbitMQ的开发者们一直在升级相关的算法,但是效果始终不太理想,尤其是在 消息量特别大的时候。

惰性队列会将接收到的消息直接存入文件系统,而不管是持久化的或者是非持久化的,这样可以减少内存的消耗,但是会增加I/O的使用,如果消息是持久化的,那么这样的I/O操作不可避免,惰性队列和持久化的消息可谓是“最佳拍档”。注意如果惰性队列中存储的是非持久化的消息,内存的使用率会一直很稳定,但是重启之后消息一样会丢失。

队列具备两种模式:defaultlazy。默认的为default模式,lazy模式即为惰性队列的模式,可以通过调用channel.queueDeclare()方法的时候在参数中设置,也可以通过Policy的方式设置,如果一个队列同时使用这两种方式设置,那么Policy的方式具备更高的优先级。如果要通过声明的方式改变已有队列的模式,那么只能先删除队列,然后再重新声明一个新的。

死信队列

DLX(Dead-Letter-Exchange),可以称为死信交换器。当消息在一个队列中变成死信(dead message)之后,它能被重新发送到另一个交换器中,这个交换器就是DLX,绑定DLX的队列就称为死信队列

消息什么情况下变成死信:

  • 消息被拒绝(channel.basicNack或channel.basicReject),并且设置requeue参数为false;
  • 消息过期;
  • 队列达到最大长度。

死信队列案例:

 private void btnBasicPublish_Click(object sender, EventArgs e)
        {
            string exchangeName = "myexchange1";
            string queueName = "myqueue3";
            string bindingKey = "myroutingkey3";
            string routingKey = "myroutingkey3";
            //创建死信交换器、队列
            this.CreateDeadQueue();
            using (var channel = connection.CreateModel())
            {
                channel.ExchangeDeclare(exchangeName, ExchangeType.Direct, true, false, null);
                channel.QueueDeclare(queueName, true, false, false,
                    new Dictionary<string, object> {
                        { "x-message-ttl", 5000 },//过期时间5s
                    { "x-dead-letter-exchange", DEAD_EXCHANGE_NAME },//死信队列交换机
                    { "x-dead-letter-routing-key", DEAD_QUEUE_NAME }//死信队列routingKey
                    });
                channel.QueueBind(queueName, exchangeName, bindingKey, null);

                //消息持久化
                var properties = channel.CreateBasicProperties();
                properties.Persistent = true;//相当于设置DeliveryMode=2

                //5:发布消息
                for (int i = 0; i < 5; i++)
                {
                    var msg = Encoding.UTF8.GetBytes($"{i}:haha");
                    channel.BasicPublish(exchangeName, routingKey, properties, msg);
                }
            }
        }


/// <summary>
        /// 创建死信交换器、死信队列、并绑定
        /// 死信交换器、队列就是一个普通交换器、队列
        /// </summary>
        private void CreateDeadQueue()
        {
            using (var channel = connection.CreateModel())
            {
                channel.ExchangeDeclare(DEAD_EXCHANGE_NAME, ExchangeType.Direct, true, false, null);
                channel.QueueDeclare(DEAD_QUEUE_NAME, true, false, false, null);
                channel.QueueBind(DEAD_QUEUE_NAME, DEAD_EXCHANGE_NAME, DEAD_QUEUE_NAME, null);
            }
        }

延时队列

延时队列存储的对象是对应的延迟消息,延迟消息指当消息被发送到队列后,并不立即被消费者拿到消息,而是等待特定的时间后,消费者才能拿到消息。
在RabbitMQ中,延时队列通过前面的DLXTTL共同作用可以模拟出延迟队列功能。
延时队列需要安装一个插件,下载

延时队列应用场景有:

  • 在订单系统中,用户下单后,通常有30分钟的付款时间。如果30分钟后没有付款,则订单被取消,这里可以使用延时队列处理订单。
  • 用户通过远程控制家里的智能设备在指定时间进行工作,可以将用户指定发送到延时队列,到达时间后再推送到智能设备。

如何使用

通过声明一个x-delayed-message类型的exchange来使用delayed-messaging特性
x-delayed-message是插件提供的类型,并不是rabbitmq本身的

Map<String, Object> args = new HashMap<String, Object>();
args.put("x-delayed-type", "direct");
channel.exchangeDeclare("my-exchange", "x-delayed-message", true, false, args);

发送消息的时候通过在header添加x-delay参数来控制消息的延时时间

byte[] messages= "delayed payload".getBytes("UTF-8");
Map<String, Object> headers = new HashMap<String, Object>();
headers.put("x-delay", 5000);
AMQP.BasicProperties.Builder properties = new AMQP.BasicProperties.Builder().headers(headers);
channel.basicPublish("my-exchange", "", properties.build(), messages);

参考:
https://blog.csdn.net/yaomingyang/article/details/102753004

posted @ 2020-07-21 23:46  .Neterr  阅读(1054)  评论(0编辑  收藏  举报