web-dev-qa-db-ja.com

AWS SQSメッセージを継続的にリッスンするパターン

AWS SQS SDK for Javaのメソッドをラップするいくつかのメソッドを持つQueueServiceという名前の単純なクラスがあります。例えば:

_public ArrayList<Hashtable<String, String>> receiveMessages(String queueURL) {
        List<Message> messages = this.sqsClient.receiveMessage(queueURL).getMessages();

        ArrayList<Hashtable<String, String>> resultList = new ArrayList<Hashtable<String, String>>();
        for(Message message : messages) {
            Hashtable<String, String> resultItem = new Hashtable<String, String>();
            resultItem.put("MessageId", message.getMessageId());
            resultItem.put("ReceiptHandle", message.getReceiptHandle());
            resultItem.put("Body", message.getBody());
            resultList.add(resultItem);
        }
        return resultList;
    }
_

Appを持つmainという名前の別のクラスがあり、QueueServiceのインスタンスを作成します。

キュー内の新しいメッセージをリッスンするmain内のAppを作成する「パターン」を探しています。現在、receiveMessagesmethodを呼び出すwhile(true)ループがあります。

_while(true) {
            messages = queueService.receiveMessages(queueURL); 
            for(Hashtable<String, String> message: messages) {
                String receiptHandle = message.get("ReceiptHandle");
                String messageBody = message.get("MessageBody");
                System.out.println(messageBody);
                queueService.deleteMessage(queueURL, receiptHandle);
            }
        }
_

これは正しい方法ですか? SQS SDKで非同期メッセージ受信メソッドを使用する必要がありますか?

10
Francisco Hanna

私の知る限り、Amazon SQSでは、Amazon SQSがリスナーにメッセージを「プッシュ」したり、メッセージがあるときにメッセージリスナーを呼び出したりするアクティブリスナーモデルをサポートする方法はありません。

したがって、常にメッセージをポーリングする必要があります。ポーリングでサポートされているポーリングメカニズムは、短期ポーリングと長期ポーリングの2つです。それぞれに長所と短所がありますが、ほとんどの場合、通常はロングポーリングが使用されますが、デフォルトはショートポーリングです。ロングポーリングメカニズムは、ネットワークトラフィックの点で間違いなくより効率的であり、コスト効率が高くなります(Amazonは行われたリクエストの数に応じて料金を請求するため)。 〜=できるだけ早く処理します)。

ロングポーリングとショートポーリングには、知る価値のある複雑な要素がありますが、ここですべてを言い換えることは多少困難ですが、必要に応じて、次のブログで詳細を読むことができます。役立つはずのコード例もいくつかあります。

http://pragmaticnotes.com/2017/11/20/Amazon-sqs-long-polling-versus-short-polling/

While(true)ループに関しては、それは依存すると言うでしょう。ロングポーリングを使用していて、待機時間を(最大)20秒に設定できる場合、メッセージがない場合は20秒より頻繁にSQSをポーリングしません。メッセージがある場合は、頻繁にポーリングするか(メッセージが到着したらすぐに処理するか)、または常に時間間隔で処理するか(たとえばn秒ごと)を決定できます。

もう1つの注意点は、1つのreceiveMessagesリクエストで最大10個のメッセージを読み取ることができるため、SQSへの呼び出し回数が減り、コストが削減されることです。また、上記のブログで詳細に説明しているように、10個のメッセージを読むようにリクエストすることもできますが、キューに多くのメッセージがある場合でも10個のメッセージを返さないことがあります。

ただし、一般的には、while(true)種類の構造を使用している場合は、実行時にポーリングをオフにするために適切なフックと例外処理を構築する必要があると思います。

考慮すべきもう1つの側面は、メインアプリケーションスレッドでSQSをポーリングするか、別のスレッドを生成するかです。したがって、別のオプションは、メインの単一スレッドでScheduledThreadPoolExecutorを作成して、スレッドを定期的(数秒ごと)にポーリングするようにスケジュールし、while(true)構造は必要ない場合があります。

14
Amitkumar Gupta

不足していることがいくつかあります。

  • receiveMessages(ReceiveMessageRequest)を使用し、待機時間を設定して長いポーリングを有効にします。
  • AWS呼び出しをtry/catchブロックでラップします。特に、OverLimitExceptionに注意してください。これは、処理中のメッセージが多すぎる場合にreceiveMessages()からスローされる可能性があります。
  • whileループの本体全体を独自のtry/catchブロックでラップし、キャッチされた例外をログに記録します(あるべきではありません-これは、AWSが変更されたためにアプリケーションがクラッシュしないようにするためです。それらのAPIまたはあなたが予期される例外を処理することを怠った場合)。

長いポーリングと考えられる例外の詳細については、 doc を参照してください。

非同期クライアントの使用に関して:使用する特別な理由はありますか?そうでない場合は、しないでください。単一のレシーバースレッドを管理する方がはるかに簡単です。

2
guest

SQSを使用してからlambdaを使用してリクエストを処理する場合は、 link に記載されている手順に従うか、SQSの代わりに常にlambdaを使用して、リクエストごとにラムダを呼び出します。

0
jpdave