RabbitMQ の電流制限、リターンメカニズム、デッドレターキュー

目次

アドバンテージ

欠点がある

1. 電流制限

2.リターン機構

3. デッドレターキュー


アドバンテージ

  1. 高可用性: RabbitMQ は、高可用性を実現し、システムの安定した動作を保証するために、クラスターやミラーリングされたキューなどの複数の方法をサポートします。

  2. 強力な信頼性: RabbitMQ は、メッセージ配信の標準として AMQP プロトコルを使用しており、メッセージ配信の信頼性と順序性を保証できます。

  3. 強力な柔軟性: RabbitMQ は、ポイントツーポイント、パブリッシュ/サブスクライブ、ルーティング、RPC などの複数のメッセージ モードをサポートしており、ビジネス ニーズに応じて適切なモードを選択できます。

  4. 優れたパフォーマンス: RabbitMQ は Erlang 言語に基づいて開発されており、高い同時実行性と低い遅延を特徴としており、大量のデータとメッセージの高速処理をサポートします。

  5. 導入と管理が簡単: RabbitMQ は、構成、監視、管理を容易にするための豊富な管理ツールと API インターフェイスを提供します。同時に、操作をより簡単かつ理解しやすくするためのビジュアルインターフェイスも提供します。

  6. オープンソースで無料: RabbitMQ はオープンソース ソフトウェアであり、完全に無料で使用できます。あらゆる環境に簡単に導入して使用できます。

欠点がある

  1. 学習コストが高い: RabbitMQ には多くの概念とテクノロジが含まれており、初心者にとっては学習が難しい場合があります。

  2. 複雑な構成: RabbitMQ の構成は比較的複雑であり、実際のニーズに応じて対応する設定を行う必要があります。構成が正しくないと、システムのパフォーマンスと安定性に影響が出る可能性があります。

  3. リソース使用率が高い: RabbitMQ は Erlang 言語を使用して開発されており、多くのメモリと CPU リソースを必要とするため、低構成のサーバーにデプロイすると、システムの遅延やその他の問題が発生する可能性があります。

  4. 単一障害点: RabbitMQ はクラスター モードをサポートしていますが、場合によっては依然として単一障害点が存在します。

  5. メッセージの蓄積: コンシューマのメッセージ処理が遅すぎる場合、または異常な状態が発生した場合、RabbitMQ はメッセージの蓄積やメモリ オーバーフローなどの問題を引き起こす可能性があります。

1. 電流制限

いわゆる現在の制限とは、コンシューマーが一度に消費できるメッセージの数を制限することです。

// 每次只消费1000条消息,RabbitMQ放过来的这1000条消息没有处理完,就不会再放进来新的消息
$channel->basic_qos(null, 1000, null);

この設定は通常は使用されませんが、メッセージ バックログが深刻な場合に使用されます。メッセージ バックログが深刻な場合にこの値が設定されていない場合、コンシューマがハングアップする可能性があります。

 

2.リターン機構

返されるリスナーは、一部のルーティング不可能なメッセージを処理するために使用されます。

プロデューサはエクスチェンジとルーティングキーを指定してメッセージを特定のキューに送信し、コンシューマはそのキューをリッスンして消費処理を行います。ただし、場合によっては、現在の交換が存在しない場合、またはメッセージの送信時に指定されたルーティングキーをルーティングできない場合があります。現時点で、そのような到達不能なメッセージをリッスンしたい場合は、リターン リスナーを使用する必要があります。

# 虽然定义了交换机,但是指定了一个没有绑定队列的路由键
<?php
declare(strict_types = 1);

use PhpAmqpLib\Connection\AMQPStreamConnection;
use PhpAmqpLib\Message\AMQPMessage;
use PhpAmqpLib\Exchange\AMQPExchangeType;

require __DIR__ . '/../vendor/autoload.php';

try {
    $connection = new AMQPStreamConnection('192.168.78.200', 5672, 'root', '123456');
    $channel = $connection->channel();
    // 定义一个交换机
    $channel->exchange_declare('test_return_exchange', AMQPExchangeType::DIRECT);
    $message = new AMQPMessage("Hello World!");

    // 这里我们指定了一个没有绑定队列的路由键,会导致rabbitmq找到不队列
    $channel->basic_publish($message, 'test_return_exchange', 'xxxxxx');

    while (true) {
        $channel->wait();
    }

    $channel->close();
    $connection->close();
} catch (Exception $e) {
    print_r($e->getMessage());
}

コードは正常に実行され、宣言したスイッチが作成されましたが、指定したルーティング キーにバインドされたキューが見つからなかったため、メッセージは Rabbitmq にプッシュされませんでしたが、rabbitmq がエラーを報告しなかったため、プッシュが成功したと誤解されます。

プッシュ状態を監視するために確認機構を使用しても、スイッチが見つからなかったり、ルートがキューに到達できないため、確認は監視できません。ここでは、rabbitmq のもう 1 つの高度な機能である return を使用することしかできません。次のコードは、戻りメカニズムを導入しています。

<?php
declare(strict_types = 1);

use PhpAmqpLib\Connection\AMQPStreamConnection;
use PhpAmqpLib\Message\AMQPMessage;
use PhpAmqpLib\Exchange\AMQPExchangeType;

require __DIR__ . '/../vendor/autoload.php';

try {
    $connection = new AMQPStreamConnection('192.168.78.200', 5672, 'root', '123456');
    $channel = $connection->channel();
    // 定义一个交换机
    $channel->exchange_declare('test_return_exchange', AMQPExchangeType::DIRECT);
    $message = new AMQPMessage("Hello World!");

    // 指定第三个参数mandatory为true,表示当rabbitmq无法找到路由或队列时,将消息返回给生产者
    // 这里我们指定了一个没有绑定队列的路由键,会导致rabbitmq找到不队列,进而触发return
    $channel->basic_publish($message, 'test_return_exchange', 'xxxxxx', true);

    // 监听消息未找到交换机或者未找到路由键对应的路由
    $channel->set_return_listener(function ($replyCode, $replyText, $exchange, $routingKey, $message) {
        $msg  = 'oh hoo!发生错误了'.PHP_EOL;
        $msg .= '错误码:'.$replyCode.PHP_EOL;
        $msg .= '错误信息:'.$replyText.PHP_EOL;
        $msg .= '指定的交换机:'.$exchange.PHP_EOL;
        $msg .= '指定的路由键:'.$routingKey.PHP_EOL;
        $msg .= '投递的消息:'.$message->body.PHP_EOL;
        print_r($msg);
    });

    while (true) {
        $channel->wait();
    }

    $channel->close();
    $connection->close();
} catch (Exception $e) {
    print_r($e->getMessage());
}

このとき、再度プログラムを実行するとエラーが報告されますが、ここではエラーを出力していますが、実際の運用では、指定したログデータテーブルにエラーが記録されるはずです。

# 程序返回
root@204d5054860c:/data/test-yii/web# php testReturn.php 
oh hoo!发生错误了
错误码:312
错误信息:NO_ROUTE
指定的交换机:test_return_exchange
指定的路由键:xxxxxx
投递的消息:Hello World!

 

3. デッドレターキュー

デッド レター キューは、実際にはデッド レター スイッチにバインドされた通常のキューであり、デッド レター スイッチは単なる通常のスイッチですが、デッド レターを処理するために特別に使用されるスイッチです。

デッドレター メッセージは、RabbitMQ が保証するレイヤーです。実際、デッドレター キューを使用することもできませんが、メッセージの消費が異常な場合、メッセージは別のスイッチにアクティブに配信されるか、ログ テーブルに記録されます。その後の特殊加工用です。

以下のシナリオでは、メッセージは Rabbitmq によってデッドレターと判断され、デッドレターキューに入れられます。

  • メッセージが拒否されました

  • メッセージの有効期限が切れました

  • キューの過負荷

次のシミュレーションは、メッセージが通常のキューに入れられることを示しています。このメッセージの有効期限は 10 秒に設定されています。10 秒以内にメッセージを処理するコンシューマがないため、このメッセージは期限切れになり、デッドレターになります。この時点では、メッセージは期限切れになり、デッドレターになります。 、RabbitMQ これは、コード内で宣言したデッドレター キューであるデッドレター キューに入れられます。

注: Rabbitmq にはデッド レター キューが 1 つだけではなく、複数のデッド レター キューが存在する可能性があります。デッド レター キューを指定しない場合、期限切れのメッセージは Rabbitmq によって破棄されます。

<?php
declare(strict_types = 1);

use PhpAmqpLib\Connection\AMQPStreamConnection;
use PhpAmqpLib\Message\AMQPMessage;
use PhpAmqpLib\Exchange\AMQPExchangeType;
use PhpAmqpLib\Wire\AMQPTable;

require __DIR__ . '/../vendor/autoload.php';

try {
    $connection = new AMQPStreamConnection('192.168.78.200', 5672, 'root', '123456');

    // 设置交换机名称
    $deadLetterExchangeNameName = 'dead_letter_exchange';
    $normalExchangeName = 'exchange_6';
    // 设置队列名称
    $deadLetterQueueName = 'dead_letter_queue';
    $normalQueueName = 'queue_6';
    // 设置路由键
    $deadLetterRoutingKey = 'dead_letter_key';
    $normalRoutingKey = 'route_6';

    // 创建通道
    $channel = $connection->channel();
    // 声明交换器,作为死信交换器
    $channel->exchange_declare($deadLetterExchangeNameName, AMQPExchangeType::DIRECT, false, true);
    // 声明交换器,作为普通交换器
    $channel->exchange_declare($normalExchangeName, AMQPExchangeType::DIRECT, false, true);

    $args = new AMQPTable();
    // 设置消息过期时间为25s,25秒后消息会进入死信队列
    $args->set('x-message-ttl', 25000);
    // 设置死信交换器
    $args->set('x-dead-letter-exchange', $deadLetterExchangeNameName);
    // 设置死信路由键
    $args->set('x-dead-letter-routing-key', $deadLetterRoutingKey);

    // 声明队列,作为普通队列,同时将死信队列相关参数传入
    $channel->queue_declare($normalQueueName, false, true, false, false, false, $args);
    // 声明死信队列
    $channel->queue_declare($deadLetterQueueName, false, true, false, false);

    // 将普通队列与普通交换机绑定
    $channel->queue_bind($normalQueueName, $normalExchangeName, $normalRoutingKey);
    // 将死信队列与死信交换机绑定,同时指定死信路由键
    $channel->queue_bind($deadLetterQueueName, $deadLetterExchangeNameName, $deadLetterRoutingKey);
    // 设置传递的消息
    $message = new AMQPMessage('Hello DLX Message queue_6');

    // confirm监听消息投递【与死信队列无关,仅用于排错】
    $channel->confirm_select();
    $channel->set_ack_handler(function ($message) {
        print_r('投递成功啦,消息是'.$message->body);
    }) ;
    $channel->set_nack_handler(function ($message) {
        print_r('投递失败啦,消息是'.$message->body);
    }) ;

    // return监听未找到交换机或路由问题【与死信队列无关,仅用于排错】
    $channel->set_return_listener(function ($replyCode, $replyText, $exchange, $routingKey, $message) {
        $msg  = 'oh hoo!发生错误了'.PHP_EOL;
        $msg .= '错误码:'.$replyCode.PHP_EOL;
        $msg .= '错误信息:'.$replyText.PHP_EOL;
        $msg .= '指定的交换机:'.$exchange.PHP_EOL;
        $msg .= '指定的路由键:'.$routingKey.PHP_EOL;
        $msg .= '投递的消息:'.$message->body.PHP_EOL;
        print_r($msg);
    });

    // 发送消息到RabbitMQ
    $channel->basic_publish($message, $normalExchangeName, $normalRoutingKey, true);

    while (true) {
        $channel->wait();
    }

    // 关闭通道和连接
    $channel->close();
    $connection->close();

} catch (Exception $e) {
    print_r($e->getMessage());
}

おすすめ

転載: blog.csdn.net/qq_27229113/article/details/131058185
おすすめ