2.RabbitMQ進階五中訊息模型(Net8)

peng_boke發表於2024-04-12

前言

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

相關文章