2.RabbitMQ进阶五中消息模型(Net8)

前言

RabbitMQ进阶。

官方地址:https://www.rabbitmq.com/tutorials/tutorial-one-dotnet

1.Hello World

点对点模式。

image-20240408002148485

1.1发送

发送10条消息

 internal class SendHelloWorld
 {
     public static void SendSendHelloWorldMsg(ConnectionFactory  connectionFactory)
     {
         
         using var connection = connectionFactory.CreateConnection();
         using var channel = connection.CreateModel();
         string qName = "helloqueue";
         //创建队列
         channel.QueueDeclare(queue: qName,
                  durable: false,
                  exclusive: false,
                  autoDelete: false,
                  arguments: null);
         int i = 0;
         while (i < 10)
         {
             string content = $"[Send] hello,这是第{i}条";
             byte[] body = Encoding.UTF8.GetBytes(content);
             // 发送消息
             channel.BasicPublish(exchange: "", routingKey: qName, null, body);
             Console.WriteLine($"发送第{i}条完毕");
             i++;
         }
     }
 }

运行:

image-20240408222242022

1.2接收

接收消息

  internal class ReceiveHelloWorld
  {
      public static void ReceiveHelloWorldMsg(ConnectionFactory  connectionFactory) {
          using var connection = connectionFactory.CreateConnection();
          using var channel = connection.CreateModel();
          string qName = "helloqueue";
          //创建队列 如果先启动消费者,且又不创建队列,程序异常
          channel.QueueDeclare(qName, false, false, false, null);
          var consumer = new EventingBasicConsumer(channel);
          consumer.Received += (model, ea) =>
          {
              var body = ea.Body.ToArray();
              var message = Encoding.UTF8.GetString(body);
              Console.WriteLine($"[Received] {message}");
          };
          channel.BasicConsume(queue: qName,
                               autoAck: true,
                               consumer: consumer);
      }
  }

运行:

image-20240408222324939

此时队列消息已被消费完毕。

image-20240407210137044

1.3默认交换机

如果发送端并没有指定交换机

image-20240407210548735

没有交换机走默认的交换机

image-20240407210736832

2.签收和拒绝

消息没有被消费。

image-20240408222405498

自动签收,队列被消费掉了。

image-20240408222441277

拒绝签收后消息回到原来的队列,会一直接收和返回。

image-20240408222510602

消息拒绝后不返回队列,消息就没了。

 channel.BasicReject(deliveryTag: ea.DeliveryTag, requeue: false);

image-20240408222540019

3.Work Queues

工作队列模式。

image-20240408002205181

模拟俩个客户端,手动签收,并且第二个客户端修休眠时间200ms,模拟处理消息慢。

image-20240408004633349

先启动来个客户端,等待接收消息。

image-20240408004751923

新建100条消息,俩个客户端开始接收消息,明显下面那个处理的更快,接收的更多,因为休眠时间短。

image-20240408004513620

4.Publish/Subscribe

发布订阅模式(广播、扇形)。

image-20240408004950995

创建交换机pubsubexchange,并绑定三个队列,向交换机pubsubexchange发送10条消息,pubsubexchange绑定的每个队列都收到了消息。

image-20240408011400307

客户端指定queueName2消费了10条消息。

image-20240408011536714

5.Routing

路由模型。

image-20240408011926789

创建direct模式的交换机routingexchange,然后指定key1发送消息。

image-20240408014219087

只消费routingqueue1的消息。

image-20240408014624809

6.Topics

主题模式。

image-20240408014704735

路由模式和主题模式主要是交换机类型和匹配规则不一样。

创建direct模式的交换机topicsexchange,然后指定key.*和key.#发送消息。

key.*后面匹配一个单词。

key.#后面匹配一个或多个单词。

所以topicsqueue1和topicsqueue1复合匹配规则,接收到了消息。

image-20240408015354821

这里只处理队列topicsqueue1的消息,topicsqueue1的消息被消费了。

image-20240408015908040

7.消息持久化和非持久化

重启服务器后之前创建的交换机和队列都没有了。

image-20240408195729313

7.1持久化

  • 内存到磁盘。保证:消息确认签收之前,不能丢。

  • 要做到消息持久化,必须:交换机、队列、消息都要持久化。

  • 持久化的交换机可以绑定没有持久化的队列;持久化的队列里可以放非持久化消息。

交换机持久化

 using var connection = connectionFactory.CreateConnection();
 using var channel = connection.CreateModel();
 // 声明交换机对象
 string exchangeName = "topicsexchange";//交换机名称
 channel.ExchangeDeclare(exchangeName, "topic", durable: true);//扇形输出 durable持久化

队列持久化

 // 创建队列 持久化
 string queueName1 = "topicsqueue1";
 channel.QueueDeclare(queueName1, durable: true, false, false, null);

消息持久化

// 信道创建属性
var prop = channel.CreateBasicProperties();
// 消息持久化
prop.Persistent = true;

持久化:

image-20240408195540364

创建的交换机和队列都变成了持久化。

D:代表持久化。

image-20240408195915587

7.2非持久化

能持久化,但是一般不做。内存快耗尽的时候进行持久化。

未持久化。

image-20240408200143884

8.死信队列

RabbitMQ 里,当消息在队列中变成死信(消费者无法正常处理的消息)之后,它会被重新投递到一个交换机上(即死信交换机),死信交换机上绑定的消费队列就是死信队列

image-20240408203145231

死信产生需要满足如下条件:

  • 消息被消费者手动拒绝接收,并且 requeue(重新加入队列)策略为 False;
  • 消息已经过期(TTL);
  • 队列达到最大长度,消息装不下了。

8.1超时

模拟一下超时后的死信队列。

将正常队列绑定死信交换机。

 Dictionary<string, object> para = new Dictionary<string, object>();
 para.Add("x-dead-letter-exchange", deadExName);//死信交换机名称
 para.Add("x-dead-letter-routing-key", deadKey);//死信路由名称
 //para.Add("x-max-length",10);//最多10条
 channel.QueueDeclare(normalQueName, false, false, false, para);

设置消息10s超时,然后自动回到私信队列。

  //发送消息(向正常队列发送) 
  var prop = channel.CreateBasicProperties();
  prop.Expiration = "10000";//设置有效期 毫秒
  
  
  channel.BasicPublish(exchange: normalExName, routingKey: normalKey, prop, body);

10s后normalqueue的信息未消费,未消费的消息重新绑定到deadqueue。

image-20240408205030640

8.2正常情况

消息在10s被正常消费吗,就不会进入死信队列。

image-20240408222642282

8.3消费死信队列

死信队列消息被消费完了。

image-20240408222718689

8.4死信队列大小限制

发送20条消息,normalqueue队列最大保存10条,还有10条进入到死信队列。

Dictionary<string, object> para = new Dictionary<string, object>();
para.Add("x-dead-letter-exchange", deadExName);//死信交换机名称
para.Add("x-dead-letter-routing-key", deadKey);//死信路由名称
para.Add("x-max-length",10);//最多10条
channel.QueueDeclare(normalQueName, false, false, false, para);

image-20240408214543332

8.5死信队列消费端拒收

拒绝的10条消息进入到死信队列。

var consumer = new EventingBasicConsumer(channel);//消费者
consumer.Received += (m, e) =>
{
    string msg = Encoding.UTF8.GetString(e.Body.ToArray());
    // requeue: false 拒绝的消息是否回到原队列(normalqueue)
    channel.BasicReject(e.DeliveryTag, requeue: false);
    Console.WriteLine("已经消费了正常队列消息:" + msg);
};

channel.BasicConsume("normalqueue", false, consumer);

image-20240408214928722

如果requeue=false拒绝的消息回到队列并且autoAck=false不自动接收,会出现死循环。

消费端一直接收一直拒绝。

 channel.BasicReject(e.DeliveryTag, requeue: false);

image-20240408222802435

9.延时队列

9.1安装延时队列插件

地址:https://www.rabbitmq.com/community-plugins

搜索rabbitmq_delayed_message_exchange

image-20240408220725967

下载

image-20240408220753754

执行一下命令:

第一步:将插件文件复制到docker容器

docker cp 
插件地址\rabbitmq_delayed_message_exchange-3.13.0.ez 
RabbitMQ容器id
:/opt/rabbitmq/plugins/rabbitmq_delayed_message_exchange-3.13.0.ez

# 例子:
docker cp C:\rabbitmq_delayed_message_exchange-3.13.0.ez 9dcba3e045fc:/opt/rabbitmq/plugins/rabbitmq_delayed_message_exchange-3.13.0.ez

可以通过命令查看RabbitMQ容器id,也可以docker desktop查看

image-20240408221708286

第二步:进入docker容器

docker exec -it rabbitmq bash

第三步:启用插件

rabbitmq-plugins enable rabbitmq_delayed_message_exchange

image-20240408221622348

刷新界面,Exchanges界面Type增加x-delayed-message。

image-20240408222040793

9.2延时队列

type: "x-delayed-message"表示延时类型交换机。

"x-delayed-type", "direct" 并且是direct模式。

 // 定义一个延时类型的交换机
 string exchangeName = "delayedexchange";
 channel.ExchangeDeclare(
     exchangeName,
     type: "x-delayed-message",
     durable: false,
     autoDelete: false,
     arguments: new Dictionary<string, object>
     {
         { "x-delayed-type", "direct" }
     }
 );

"x-delay",10000表示消息延迟10s发送。

var body = Encoding.UTF8.GetBytes("这是我发送的延时消息");
var prop = channel.CreateBasicProperties();
prop.Headers = new Dictionary<string, object>() {
        { "x-delay",10000}//延时10秒
};
channel.BasicPublish(exchangeName, key, basicProperties: prop, body: body);

10s之后把消息发送到队列。

image-20240408224146767

创作不易,感谢支持。

wxzf
posted @   peng_boke  阅读(190)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示