RabbitMQ (冪等、プライオリティ キュー、レイジー キュー)

目次

1.冪等性

1.1 繰り返されるメッセージ消費

1.2 消費者側の冪等性の保証

2.優先キュー

2.1 使用シナリオ

2.2 プライオリティ キューの設定 (Web ページで追加)

2.3 優先度キューの設定 (キュー宣言時に優先度を追加)

2.4 サンプルコード

3.レイジーキュー

3.1 使用シナリオ

3.2 キューの 2 つのモード

3.3 宣言方法

3.4 メモリオーバーヘッドの比較

1.冪等性

        冪等性とは 同じ操作に対してユーザーが開始した 1 つまたは複数の要求の結果は一貫しており、複数のクリックによる副作用はありません。

        決済を例にとると、ユーザーは商品を購入した後に決済を行い、決済は成功するが、結果が返ってきた場合はネットワークが異常であり、この時点でお金が差し引かれ、ユーザーが再度ボタンをクリックすると、 、この時点で2回目の控除が行われ、返品結果は成功です.ユーザーが残高を確認したところ、さらにお金が差し引かれていることがわかり、取引記録が2つになりました[明らかにこれは問題です].

        以前の単一アプリケーション システムでは、データ操作をトランザクションに入れて、エラーが発生したときにすぐにロールバックするだけで済みました。

1.1 繰り返されるメッセージ消費

        コンシューマーが MQ でメッセージをコンシュームすると、MQ はコンシューマーにメッセージを送信し、コンシューマーが MQ に ack を返すとネットワークが中断されるため、MQ は確認メッセージを受信せず、メッセージは他のコンシューマーに再送信されます。または、ネットワークが再接続された後に再度コンシューマーに送信しますが、実際にはコンシューマーはメッセージを正常に消費したため、コンシューマーは重複したメッセージを消費します。

ソリューション:

        MQ コンシューマのべき等性に対するソリューションは、通常、グローバル ID を使用するか、タイムスタンプや UUID などの一意の識別子を書き込むか、独自のルールに従ってグローバルに一意の ID を生成します。メッセージが消費されるたびに、ID が最初に使用されますメッセージが処理されたかどうかを判断します

        一度しか入力できない確認コードとも理解でき、再入力すると確認コードが更新され、元の確認コードは無効になります。

1.2 消費者側の冪等性の保証

        大量の注文が発生するビジネスのピーク時には、生産側がメッセージを繰り返し送信する場合があります. このとき、消費者側は冪等性を達成する必要があります。同じメッセージ。

業界で主流の冪等性には、次の 2 つの操作があります。

  • データベースの主キーを使用して重複排除する一意の ID + 指紋コード メカニズム

        指紋コード: 一部のルールまたはタイムスタンプとその他のサービスによって提供される一意の情報コード. 必ずしもシステムによって生成されるとは限りません. 基本的にビジネスルールによって接合されます, しかし、一意性は保証されなければなりません. 次に、クエリを使用しますid がデータベースに存在するかどうかを判断するステートメント.利点は単純なスプライシングを実現し、それが繰り返されるかどうかを判断するクエリ. 欠点は、同時実行性が高い場合、単一のデータベースの場合、もちろん、サブデータベースとサブテーブルを使用してパフォーマンスを向上させることもできますが、この方法はお勧めしません。

  • Redis の原子性 (推奨)

        redis を使用して setnx コマンドを実行すると、自然に冪等になります。非反復消費を達成するために。

2.優先キュー

2.1 使用シナリオ

        たとえば、顧客が特定の宝物を注文した場合、特定の宝物は注文を時間内にプッシュし、ユーザーが設定した時間内に支払いが行われない場合、ユーザーに SMS リマインダーを送信します。

        しかし、モバオの場合は大口顧客と小口顧客に分ける必要があり、例えばAppleやXiaomiのような大企業は1年で多くの利益を上げることができるため、注文を優先しなければならないのは当たり前のことです。したがって、RabbitMQ は、注文量が多い後の変換と最適化に使用され、注文が大口顧客であることが判明した場合は比較的高い優先度が与えられ、それ以外の場合はデフォルトの優先度になります。

2.2 プライオリティ キューの設定 (Web ページで追加)

キューの最大優先度は 255 まで設定できます。公式 Web サイトでは 1 ~ 10 が推奨されています。設定が高すぎると、メモリと CPU を消費します。

2.3 優先度キューの設定 (キュー宣言時に優先度を追加)

キューの最大優先度は 255 まで設定できます。公式 Web サイトでは 1 ~ 10 が推奨されています。設定が高すぎると、メモリと CPU を消費します。

Map<String, Object> params = new HashMap();
// 优先级为 10
params.put("x-max-priority", 10);
channel.queueDeclare("hello", true, false, false, params);

予防:

        (1) キューをプライオリティキューとして設定する必要があり、メッセージにはメッセージの優先度を設定する必要があり、両方が設定されている場合にのみ優先度をソートできます。

        (2)コンシューマーは、メッセージを消費する前にメッセージがキューに送信されるのを待つ必要があります。これは、この方法でメッセージをソートする機会があるためです。

2.4 サンプルコード

        プロデューサは 10 個のメッセージを送信します. メッセージが の場合 info5, 優先度が最も高くなります. コンシューマがキューからメッセージを取得するとき, info5 最初にメッセージを取得します.

1.プロデューサーコード

public class PriorityProducer {

    private static final String QUEUE_NAME = "priority_queue";

    public static void main(String[] args) throws Exception {
        Channel channel = RabbitMQUtils.getChannel();

        //给消息赋予一个priority属性
        AMQP.BasicProperties properties =
                new AMQP.BasicProperties().builder().priority(5).build();

        //设置队列的最大优先级 最大可以设置到255 官网推荐1-10 如果设置太高比较吃内存和CPU
        Map<String, Object> params = new HashMap<>();
        params.put("x-max-priority",10);
        channel.queueDeclare(QUEUE_NAME,true,false,false,params);

        for (int i = 1; i < 11; i++) {
            String message = "info"+i;
            if(i==5){
                channel.basicPublish("",QUEUE_NAME,properties,message.getBytes());
            }else {
                channel.basicPublish("",QUEUE_NAME,null,message.getBytes());
            }
            System.out.println("消息发送完成:"+message);
        }
    }
}

2. 消費者コード

public class PriorityConsumer {

    private final static String QUEUE_NAME = "priority_queue";

    public static void main(String[] args) throws Exception {
        Channel channel = RabbitMQUtils.getChannel();

        //推送消息如何进行消费的接口回调
        DeliverCallback deliverCallback = (consumerTag, delivery) ->{
            String message = new String(delivery.getBody());
            System.out.println("消费的消息: "+message);
        };

        //取消消费的一个回调接口 如在消费的时候队列被删除掉了
        CancelCallback cancelCallback = (consumerTag) ->{
            System.out.println("消息消费被中断");
        };

        channel.basicConsume(QUEUE_NAME,true,deliverCallback,cancelCallback);
    }
}

3.効果のデモンストレーション

info 5 の優先度は 5 で、最高の優先度です。消費者の消費情報の影響を図に示します。

3.レイジーキュー

3.1 使用シナリオ

        バージョン 3.6.0 以降、RabbitMQ は遅延キューの概念を導入しました。The lazy queue will store the message on the disk as much as possible, and will be loaded into the memory when the consumer uses the対応するメッセージ. その重要な設計目標の 1 つは、より長いキューをサポートできるようにすることです。より多くのメッセージ ストレージ。さまざまな理由 (コンシューマーのオフライン、ダウンタイム、またはメンテナンスによるシャットダウンなど) により、コンシューマーが長時間メッセージをコンシュームできない場合、不活性キューが必要です。

        デフォルトでは、プロデューサーがRabbitMQにメッセージを送信すると、キュー内のメッセージは可能な限りメモリに保存されるため、メッセージをより迅速にコンシューマーに送信できます。永続メッセージでさえ、ディスクに書き込まれるときにメモリ内コピーを持ちます。RabbitMQ がメモリを解放する必要がある場合、メモリ内のメッセージをディスクにページングします. この操作には時間がかかり、キューの操作もブロックされるため、新しいメッセージを受信できません. RabbitMQ の開発者は関連するアルゴリズムをアップグレードしてきましたが、特にメッセージの量が特に多い場合、効果は理想的ではありません。

3.2 キューの 2 つのモード

        キューには、デフォルトとレイジーの 2 つのモードがあります。デフォルト モードは default で、3.6.0 より前のバージョンでは変更する必要はありません。レイジー モードはレイジー キューのモードです. メソッドを呼び出すときにパラメータで設定するか channel.queueDeclare , ポリシー モードで設定できます. キューが同時に両方の方法で設定されている場合, ポリシー モードはより高い優先度。宣言によって既存のキューのモードを変更する場合は、最初にキューを削除してから、新しいキューを再宣言することしかできません。

3.3 宣言方法

        キューを宣言するとき、 x-queue-mode パラメーターを介してキューのモードを設定できます。値はデフォルトとレイジーです。次の例は、遅延キューの宣言の詳細を示しています。

Map<String, Object> args = new HashMap<String, Object>();
args.put("x-queue-mode", "lazy");
channel.queueDeclare("myqueue", false, false, false, args);

        Web ページにキューを追加することもできます Lazy mode:

3.4 メモリオーバーヘッドの比較

        100 万通のメッセージを送信し、各メッセージが約 1KB を占有する場合、通常のキューが占有するメモリは 1.2GB ですが、レイジー キューは 1.5MB しか占有しません。

        2 つのモードにはそれぞれ長所と短所があり、適切な方が最適であり、実際のアプリケーションはビジネス シナリオに従って選択する必要があります。

おすすめ

転載: blog.csdn.net/friggly/article/details/127734070