RabbitMQ實現延遲佇列

streetlamp發表於2022-04-22
  • 實現原理:給佇列的訊息設定過期時間(TTL),訊息到期後就會投遞到一個死信佇列,我們就可以在這裡處理延遲的任務。

    一、介紹

    1. 死信佇列

    當訊息在一個佇列中變成死信之後,它會被重新投遞到設定的Exchange中,這個Exchange就是DLX,透過routing_key的繫結投遞到對應的佇列,這個佇列就是死信佇列。

    2. 死信訊息
    • 訊息被拒絕(basic.reject / basic.nack),並且requeue = false。
    • 訊息TTL過期。TTL:Time To Live的簡稱,即過期時間。
    • 佇列達到最大長度。
    3. 過期訊息
    • 透過佇列進行設定,設定後該佇列所有的訊息都存在相同的過期時間。
    • 透過對訊息本身設定,佇列中的每條訊息的過期時間都可以不一樣。如果要用來實現延遲佇列不建議使用這種方式,因為佇列只會判斷第一個訊息是否過期,過期則把訊息投遞到死信佇列。如果第一個訊息過期時間為30s,二個訊息的過期時間為10s,那麼佇列等30s後把第一訊息投遞到死信佇列,然後繼續判斷下一個訊息,但是這樣子第二個訊息的延遲時間就變成30s了。

    二、原理圖

    RabbitMQ實現延遲佇列

    三、上程式碼

    composer require php-amqplib/php-amqplib
    把程式碼貼到根目錄的public.php檔案執行

      <?php
    
      use PhpAmqpLib\Message\AMQPMessage;
    
      require_once __DIR__ . '/vendor/autoload.php';
      //配置資訊
      $conn_args       = array(
          'host'     => '47.107.237.18',
          'port'     => '5672',
          'login'    => 'guest',
          'password' => 'guest',
          'vhost'    => '/'
      );
      $ttl             = 10;//過期時間
      $exchange        = 'exchange';//正常交換機
      $delayExchange   = 'delayed_' . $exchange;//死信交換機
      $type            = 'topic';
      $msg             = 'hello world';
      $route           = 'delay';
      $deadQueue       = 'dead_queue';//死信佇列
      $delayQueue      = 'delayed_queue_' . $exchange . '_' . $ttl;//延遲佇列
      $delayRoutingKey = $route . '_' . $ttl;
    
      $conn = new \PhpAmqpLib\Connection\AMQPStreamConnection(
          $conn_args['host'],
          $conn_args['port'],
          $conn_args['login'],
          $conn_args['password'],
          $conn_args['vhost']
      );
      //建立連線和channel
      $channel = $conn->channel();
      //定義延遲交換器
      $channel->exchange_declare($delayExchange, 'topic', false, true, false);
      //定義延遲佇列,
      $channel->queue_declare(
          $delayQueue,
          false,
          true,
          false,
          false,
          false,
          new \PhpAmqpLib\Wire\AMQPTable(
              array(
                  "x-dead-letter-exchange"    => $delayExchange,/*佇列資訊超時後投遞到這個交換機*/
                  "x-dead-letter-routing-key" => $route,/*routingKey*/
                  "x-message-ttl"             => $ttl * 1000,/*超時時間*/
              )
          )
      );
      /*定義死信佇列,延遲佇列超時的訊息就會投遞到這裡處理*/
      $channel->queue_declare(
          $deadQueue,
          false,
          true,
          false,
          false
      );
      /*繫結死信佇列到延遲交換機*/
      $channel->queue_bind($deadQueue, $delayExchange, $route);
      //繫結延遲佇列到交換器上
      $channel->queue_bind($delayQueue, $delayExchange, $delayRoutingKey);
      //生產者傳送訊息
      $msg = new AMQPMessage($msg);
      $channel->basic_publish($msg, $delayExchange, $delayRoutingKey);
      $channel->close();

謝謝觀看,日常記錄!
streetlamp 敬上!

本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章