web-dev-qa-db-ja.com

SQSで特定のメッセージを検索する

SQSがそのために構築されていないことは知っていますが、いくつかの基準を満たすメッセージをキューで見つけることができるのでしょうか。

メッセージをループでプルし、メッセージ本文でパターンを検索し(逆シリアル化することなく)、必要なメッセージをフィルタリングできます。しかし、その後、無限ループになる可能性があります。最初に読んだメッセージは、キューの最後に到達するまでにキューに戻ります...

メッセージの可視性を拡張することは可能ですが、キュー全体をスキャンするのにかかる時間を正確に知るにはどうすればよいですか?また、可視性を拡張する必要がある時間はどれくらいですか?文字通り1万通のメッセージがある場合はどうなりますか?

ここに回避策はありますか?キューをスキャンしていくつかのメッセージを探し、それらを削除する必要があります...

19
iLemming

簡単な答え:いいえ。

キューは、タスクなどのために設計されています。マシンはキューから新しいタスク(つまり、メッセージ)を取得し、タスクを実行してから、タスクを削除します。

メッセージを検索してフィルタリングしようとしている場合、その仕事に間違ったツールを使用しているのではないかと思わずにはいられません…

17
Ryan Parman

短い答えも長い答えも「いいえ」ではないと思います。

これが「はい」である2つの対抗策です。

  1. キューをトラバースし、訪問者リストを維持する
  2. エンタープライズ統合パターン(メッセージルーティング)を使用して、基準に基づいてメッセージをダウンストリームに分割します

1。キューをトラバースし、訪問済みリストを維持します

Nメッセージがあり、メッセージが追加または削除されていないキューの場合を考えてみます。追加情報がない場合(たとえば、基準に一致するメッセージの数がわかっている場合)、すべてのNメッセージをトラバースする必要があります。

ここで重要なのは、すべてのNメッセージをいつトラバースしたかを知ることです。ここにはいくつかの問題があります。

  1. 正確に知るには、メッセージがキューに追加されるときにメッセージを追跡する必要があります
  2. おおよその知識を得るには、キューのApproximateNumberOfMessages属性を取得できます
  3. または、訪問済みリストを維持しながらループでメッセージを受信し、最終的にキューがシャーディングされた各サーバーからメッセージをサンプリングして使い果たすと想定することもできます

訪問者リストを維持するために、メッセージを受信して​​一致基準を評価するときに、すべての訪問者メッセージのmessage_idを保存できます。

メッセージIDはほぼ一意です。このスレッドを参照してください

https://forums.aws.Amazon.com/message.jspa?messageID=76119

(3)を使用した場合、キューを使い果たすために何回の反復が必要になるかはわかりません。ただし、これを無期限に実行した場合、SQSシャードサーバー上での加重ランダム分散によってすべてがゼロ以外の確率になる限り、キューを吐き出すことが保証されます。

2。エンタープライズ統合パターン(メッセージルーティング)を使用して、基準に基づいてメッセージをダウンストリームに分割します

メッセージングアーキテクチャを制御できる場合は、基準に基づいてさまざまな受信者にメッセージをディスパッチする「フロントエンド」メッセージプロセッサとしてメッセージルーターを使用できます。

具体的には、コンテンツベースのルーターを使用します。

http://www.enterpriseintegrationpatterns.com/patterns/messaging/ContentBasedRouter.html

5
mcg256

OKこの質問はずっと前のものであり、属性が彼の説明どおりに機能するというドロン-BGUbguの主張もそうです。

同じJSONをSQSに送信する「プロデューサー」が何人かいました。「コンシューマー」は、モバイルクライアント、MVCクライアント、またはその他の社内デスクトップアプリの発信元に応じて、異なる方法でダンスを行う必要がありました。

私は真剣にドロンをテストしたい-BGUbguの理論は本当に悪い。しかし、実用的であるために、キューからのこれらのメッセージに対して明らかに異なるプロセスを実行した私の単一のコンシューマーは、メッセージのソースを定義するプロデューサーに入力を強制したJSONの値についてそれぞれをチェックしました。りんごはあちらオレンジをあちらに行きます。

0

いくつかの例でこれを理解しましょう。10個のメッセージを作成して送信します

// Send a message
for (int i = 0; i < 10; i++) {
    System.out.println("Sending a message to MyQueue.\n");
    Map<String, MessageAttributeValue> messageAttributes = new HashMap<>();
    // extra code

    String sdate;
    Format formatter;
    Date date = new Date();

    // 2012-12-01
    formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
    sdate = formatter.format(date);
    System.out.println(sdate);

    messageAttributes.put("Datestamp"+i, new MessageAttributeValue().withDataType("String").withStringValue(sdate));

    Map<String, MessageAttributeValue> messageAttributes1 = new HashMap<>();
    messageAttributes1.put("attributeName", new MessageAttributeValue().withDataType("String").withStringValue(sdate));
    SendMessageRequest request = new SendMessageRequest();
    request.withMessageBody("A test message body."+sdate);
    request.withQueueUrl(myQueueUrl);
    request.withMessageAttributes(messageAttributes);
    sqs.sendMessage(request);
}

これで、datetimestamp1からdatetimestamp10までのメッセージが10個あります。
属性を使用したフィルタリングは機能しません

myTag属性でフィルタリングしてみましょう

ReceiveMessageRequest receiveMessageRequest = new ReceiveMessageRequest(myQueueUrl);

//ReceiveMessageRequest receiveRequest = new ReceiveMessageRequest(queueUrl);

receiveMessageRequest.withMaxNumberOfMessages(10);
receiveMessageRequest.withMessageAttributeNames("myTag");
List<Message> messages = sqs.receiveMessage(receiveMessageRequest).getMessages();

それは10のメッセージを与え、myTag値はnullです

message.getMessageAttributes()。get( "Datestamp")はnullですmessage.getMessageAttributes()。get( "myTag")はnullです

そのため、そのキーが見つからないかのようにメッセージ属性でフィルタリングすることはできません。メッセージ属性がないか、すべてのメッセージ属性が同じです。

とても長い答えはNOOOOOです

0
Jin Thakur

すべてを完全に制御する謙虚なDevOpsエンジニアの場合:

(1)コンシューマーをすばやくオフにして、メッセージがキューにキャプチャされるようにします。

(2)ソースをオフにします。

(3)「temp」キューにコピーしながら、メッセージを探してすべてのSQSキューを読み取ります。

(4)すべての「temp」キューをSQSキューにコピーして戻します。グーグルそれは多くのツールがあります。

(5)ソースとコンシューマーを再起動します。

事前に考えていた場合のもう1つの方法は、SNSなどを使用して、補助的な「devops」キューにコピーし、メッセージを見つける必要があるときにそれを読み通すことです。 'devops'キューの保持期間を短く設定して、サイズを適切に保つことができます。

0
andrew pate

特定の属性を要求する場合、属性を含まないメッセージの値はnullに設定されるだけですが、それでもある方法でフィルタリングするために使用できます。属性が希望どおりに設定されていない場合は、可視性を1に設定してから解放できるため、キューに残ります。メッセージの内容に基づいて同じように簡単に行うことができますが、優先キューイングを行うための大まかな方法​​を提供します。

0
Chris Shepley

さまざまなケースでテスト済み。それは動作しません。答えはいいえだ

TestData

public void fillQueueWithMessages(){

  MessageAttributeValue value1 = new MessageAttributeValue();
  value1.setDataType("String");
  value1.setStringValue("1");

  SendMessageRequest send_msg_request = new SendMessageRequest()
      .withQueueUrl(env.getProperty("cloud.aws.sqs.readyForTranslation.url"))
      .withMessageBody("test1").addMessageAttributesEntry(value1.getStringValue(), value1);
  amazonSqs.sendMessage(send_msg_request);


  MessageAttributeValue value2 = new MessageAttributeValue();
  value2.setDataType("String");
  value2.setStringValue("2");


  SendMessageRequest send_msg_request2 = new SendMessageRequest()
      .withQueueUrl(env.getProperty("cloud.aws.sqs.readyForTranslation.url"))
      .withMessageBody("test2").addMessageAttributesEntry(value2.getStringValue(), value2);
  amazonSqs.sendMessage(send_msg_request2);

  SendMessageRequest send_msg_request3 = new SendMessageRequest()
      .withQueueUrl(env.getProperty("cloud.aws.sqs.readyForTranslation.url"))
      .withMessageBody("test3").addMessageAttributesEntry(value1.getStringValue(), value1);
  amazonSqs.sendMessage(send_msg_request3);

}

テスト

public void shouldPollMessagesBasedOnMessageAttribute() throws InterruptedException {

ReceiveMessageRequest request =
    new ReceiveMessageRequest(env.getProperty("cloud.aws.sqs.readyForTranslation.url"));
request.setMaxNumberOfMessages(3);
request.setWaitTimeSeconds(20);
request.withMessageAttributeNames("1");

List<Message> messages = new ArrayList<Message>();

messages = amazonSqs.receiveMessage(request).getMessages();

assertEquals(2, messages.size());
}