SQS maxNumberOfMessages

11

Korzystając z aplikacji klienckiej Java, pytam o kolejkę SQS. Kolejka zawiera 12 000 komunikatów w konfiguracji do testowania. Korzystam z openJDK z najnowszą wersją aws-java-sdk (software.amazon.awssdk 2.10.62) pom.xml.

Problem, który widzę, polega na tym, że pomimo ustawienia maxNumberOfMessages (10) dostaję tylko 3. Rozumiem, że to maksimum nie jest gwarancją liczby wiadomości, jednak nie ma wahania w liczbie zwracanych wiadomości. Jest zawsze 3.

Dokumentacja AWS: MaxNumberOfMessages Maksymalna liczba komunikatów do zwrócenia. Amazon SQS nigdy nie zwraca więcej wiadomości niż ta wartość (jednak może zostać zwróconych mniej wiadomości). Prawidłowe wartości: od 1 do 10. Domyślnie: 1. Typ: Liczba całkowita Wymagana: Nie

Odbieranie wiadomości za pomocą krótkiego odpytywania

Gdy konsumujesz wiadomości z kolejki przy użyciu krótkiego odpytywania, Amazon SQS próbkuje podzbiór swoich serwerów (na podstawie ważonej dystrybucji losowej) i zwraca wiadomości tylko z tych serwerów. W związku z tym określone żądanie ReceiveMessage może nie zwrócić wszystkich wiadomości. Jeśli jednak masz mniej niż 1000 wiadomości w kolejce, kolejne żądanie zwróci wiadomości. Jeśli nadal używasz kolejek, Amazon SQS pobiera próbki ze wszystkich swoich serwerów i otrzymujesz wszystkie wiadomości.

Przetestowaliśmy więc dwóch klientów w Javie, używając zarówno starszego aws sdk, jak i nowszego z tymi samymi wynikami. Zawsze tylko 3 wiadomości z powrotem.

Co ciekawe, jeśli zamiast uruchamiać aplikację zewnętrznie (na moim potężnym komputerze), uruchomisz ją jako AWS Lambda, otrzymasz 10 wiadomości. Ten test lambda został wykonany przy użyciu JavaScript przez kolegę.

Pozostaje więc pytanie, dlaczego otrzymujemy tylko 3 wiadomości na żądanie, a pozornie w lambda można uzyskać 10.

Biorąc pod uwagę, że istnieje koszt za żądanie, jest to ważona losowa dystrybucja oparta na zysku amazonu =))

Metoda testu SQS:

public void SQStart()
{
    AwsBasicCredentials awsCreds = AwsBasicCredentials.create("accessKeyID", "secretKeyID");
    AwsCredentialsProvider creds = StaticCredentialsProvider.create(awsCreds);
    SqsClient sqs = SqsClient.builder().credentialsProvider(creds).region(Region.EU_WEST_1).build();
    GetQueueUrlRequest getQueueRequest = GetQueueUrlRequest.builder()
            .queueName(QUEUE_NAME)
            .build();
    String queueUrl = sqs.getQueueUrl(getQueueRequest).queueUrl();

    for (int x =1; x < 100; x++) {
        ReceiveMessageRequest receiveMessageRequest = ReceiveMessageRequest.builder()
                .queueUrl(queueUrl)
                .maxNumberOfMessages(10)
                .build();


        List<Message> messages = sqs.receiveMessage(receiveMessageRequest).messages();
        if (messages.size() > 3 ) {
            System.out.println("YEY More than 3 Messages: "+ messages.size());
        }
    }
}

POM.XML:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>groupId</groupId>
    <artifactId>SQSTest</artifactId>
    <version>1.0-SNAPSHOT</version>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>8</source>
                    <target>8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>


    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>software.amazon.awssdk</groupId>
                <artifactId>bom</artifactId>
                <version>2.10.62</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>

            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>software.amazon.awssdk</groupId>
            <artifactId>sqs</artifactId>
        </dependency>

        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.5.9</version>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpcore</artifactId>
            <version>4.4.10</version>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.2</version>
        </dependency>
        <dependency>
            <groupId>com.amazonaws</groupId>
            <artifactId>aws-java-sdk-s3</artifactId>
            <version>1.11.720</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-simple</artifactId>
            <version>1.6.1</version>
        </dependency>
    </dependencies>
</project>
DevilCode
źródło
To tylko myśl, ale czy sprawdziłeś konfigurację samej kolejki w AWS? Może została skonfigurowana z właściwością maxNumberOfMessages, która może mieć priorytet w stosunku do właściwości ustawionej w kliencie Java? Ponieważ działa w javascript lambda, byłoby to dziwne, ale nadal warto
spróbować

Odpowiedzi:

9

Biorąc pod uwagę, że istnieje koszt za żądanie, jest to ważona losowa dystrybucja oparta na zysku amazonu =))

Oczywiste jest, że Twoim celem jest obniżenie kosztów, czy to poprzez wysyłanie mniejszej liczby żądań do SQS, czy przez zmuszanie SQS do dostarczenia maksymalnej dostępnej liczby wiadomości.

Jak stwierdzono w swoim pytaniu, SQS nie ma obowiązku dostarczania maksymalnej dostępnej liczby wiadomości. Jest jednak coś, o czym chciałbym cię poinformować, zakładając, że jeszcze tego nie wiesz.


Długie odpytywanie

Developer Guide prostych stanach kolejki Obsługi Amazon:

Proces pobierania wiadomości z kolejki zależy od tego, czy korzystasz z krótkiego czy długiego odpytywania. Domyślnie Amazon SQS używa krótkiego odpytywania , odpytując tylko część swoich serwerów (na podstawie ważonej losowej dystrybucji), aby ustalić, czy jakieś wiadomości są dostępne do odpowiedzi. Możesz użyć długiego odpytywania, aby zmniejszyć koszty, jednocześnie umożliwiając klientom odbieranie wiadomości, jak tylko dotrą do kolejki.

Wszystkie wiadomości wysłane do SQS mogły być przechowywane na osobnych serwerach. Jak wynika z dokumentacji, można zapytać tylko o podzbiór serwerów, jeśli w kolejce ustawiono krótkie odpytywanie . Domyślam się, że miałeś pecha podczas inwokacji receiveMessagei 3za każdym razem wracałeś.

Jeśli spojrzymy na zalety długiego odpytywania na tej samej stronie dokumentacji, stwierdza:

Długie odpytywanie oferuje następujące korzyści:

  • Wyeliminuj puste odpowiedzi, pozwalając Amazon SQS czekać na wiadomość w kolejce przed wysłaniem odpowiedzi. O ile połączenie nie przekroczy limitu czasu, odpowiedź na żądanie ReceiveMessage zawiera co najmniej jeden z dostępnych komunikatów, aż do maksymalnej liczby komunikatów określonych w akcji ReceiveMessage.

  • Wyeliminuj fałszywe puste odpowiedzi, sprawdzając wszystkie - a nie podzbiór - serwerów Amazon SQS.

Druga kula jest tutaj bardzo ważna. Chociaż nie widzisz pustych odpowiedzi, może istnieć więcej wiadomości przechowywanych na serwerach, które nie są pytane. Jeśli włączysz długie odpytywanie, mam nadzieję, że zauważysz wzrost liczby zwracanych wiadomości, zakładając, że łącznie jest więcej niż 3 serwery.

Dlatego sugeruję, aby umożliwić długie odpytywanie w kolejce. Aby to zrobić, zobacz stronę Konfigurowanie długiego odpytywania .


Jak wspomniał DevilCode w swoim komentarzu poniżej, był w stanie rozwiązać swój problem, używając kolejki FIFO zamiast standardowej i umożliwiając długie odpytywanie.

Jacob G.
źródło
Testowaliśmy to samo z długim sondowaniem i otrzymaliśmy ten sam wynik. W kolejce było 12 000 wiadomości, a sondowanie ustawiono na 20 sekund. Nadal otrzymujemy tylko trzy wiadomości. Jeśli otrzymamy trzy wiadomości z długim i krótkim odpytywaniem, nie ma powodu, aby używać długiego odpytywania (z wyjątkiem sytuacji, gdy kolejka jest pusta i czeka na wiadomości). Niestety staramy się zrównoważyć koszty i szybkość. Niestety, mamy tylko ograniczone wątki odczytu, których możemy użyć (ze względu na sprzęt), więc liczba wiadomości, które możemy rozwinąć na rozmowę, jest czynnikiem ograniczającym szybkość jej przetwarzania.
DevilCode
@DevilCode Nie udało mi się odtworzyć Twojego problemu z włączonym długim odpytywaniem. Czy Twoja kolejka jest kolejką standardową czy kolejką FIFO? Możesz także otworzyć bilet pomocy technicznej w AWS, aby sprawdzić, czy mogą dokonać zmian na swoim końcu.
Jacob G.
To standardowa kolejka. Czy uruchomiłeś kod lokalnie i korzystałeś z Javy?
DevilCode
@DevilCode Przetestowałem go przy użyciu kolejki FIFO. I tak, używam AWS Java SDK v2 do otrzymywania wiadomości z mojej kolejki SQS. Mój kod nie działa w ramach funkcji AWS Lambda.
Jacob G.
1
OK Testowałem kolejkę FIFO i otrzymujemy 10 wiadomości, podczas gdy tak jak w standardowej kolejce otrzymujemy tylko trzy. Mogę tylko stwierdzić, że dokumentacja odnosi się do kolejki FIFO, a nie standardowej.
DevilCode
0

Myślę, że to jest podobnym question.As wskazanych przez Jakuba długo sondowania wydaje się być rozwiązaniem tego problemu.

charbel k
źródło
0

Długie odpytywanie:

        ReceiveMessageRequest receiveMessageRequest = new ReceiveMessageRequest(queueUrl)
              .withWaitTimeSeconds(10)     // long poll: wait 10 seconds, max is 20 seconds
              .withMaxNumberOfMessages(10);
Justin
źródło