Amazon Web Services
Allgemeine Referenz (Version 1.0)

Wiederholversuche bei Fehlern und exponentielles Backoff in AWS

Zahlreiche Komponenten im Netzwerk, wie z. B. DNS-Server, Switches und Load Balancer, können irgendwann im Lebenszyklus einer Anforderung Fehler generieren. Die übliche Methode zum Umgang mit diesen Fehlermeldungen in einer vernetzten Umgebung besteht darin, Wiederholversuche in der Client-Anwendung zu implementieren. Diese Vorgehensweise erhöht die Zuverlässigkeit der Anwendung und senkt die Betriebskosten für die Entwickler.

Jedes AWS SDK implementiert eine automatische Logik für Wiederholversuche. Bei AWS SDK for Java werden Anforderungen automatisch wiederholt. Sie können die Einstellungen für Wiederholversuche mit der Klasse ClientConfiguration konfigurieren. Sie können beispielsweise die Wiederholversuchslogik für eine Webseite deaktivieren, die eine Anforderung mit minimaler Latenz und ohne Wiederholversuche versendet. Verwenden Sie die ClientConfiguration-Klasse und geben Sie einen Wert für maxErrorRetry von 0 ein, um die Wiederholversuche zu deaktivieren.

Wenn Sie kein AWS SDK verwenden, sollten ursprüngliche Anforderungen wiederholt werden, die Serverfehler (5xx) oder Ablehnungsfehler erhalten. Client-Fehler (4xx) hingegen weisen darauf hin, dass die Anforderung geändert werden muss, um das Problem zu beheben. Erst dann sollte sie wiederholt werden.

Zusätzlich zu einfachen Wiederholversuchen implementiert jedes AWS SDK einen Algorithmus für das exponentielle Backoff, um den Fluss besser zu steuern. Die Idee hinter dem exponentiellen Backoff ist, bei aufeinander folgenden Fehlermeldungen progressiv längere Wartezeiten zwischen den Wiederholversuchen zu verwenden. Sie sollten ein maximales Verzögerungsintervall sowie eine maximale Anzahl von Wiederholversuchen implementieren. Das maximale Verzögerungsintervall und die maximale Anzahl von Wiederholversuchen sind nicht unbedingt feste Werte. Sie sollten abhängig von der durchgeführten Operation und anderen lokalen Faktoren (z. B. Netzwerklatenz) festgelegt werden.

Die meisten Algorithmen für das exponentielle Backoff verwenden Jitter (zufällige Verzögerung), um nachfolgende Kollisionen zu verhindern. Da Sie hier nicht versuchen, solche Kollisionen zu verhindern, müssen Sie diese Zufallszahl nicht verwenden. Wenn Sie jedoch gleichzeitige Clients verwenden, kann Jitter dazu beitragen, dass Ihre Anforderungen schneller verarbeitet werden. Weitere Informationen finden Sie im Blogbeitrag zu Exponentielles Backoff und Jitter.

Der folgende Pseudocode zeigt eine Möglichkeit, einen Status über eine inkrementelle Verzögerung abzufragen.

Do some asynchronous operation. retries = 0 DO wait for (2^retries * 100) milliseconds status = Get the result of the asynchronous operation. IF status = SUCCESS retry = false ELSE IF status = NOT_READY retry = true ELSE IF status = THROTTLED retry = true ELSE Some other error occurred, so stop calling the API. retry = false END IF retries = retries + 1 WHILE (retry AND (retries < MAX_RETRIES))

Der folgende Code zeigt, wie diese inkrementelle Verzögerung in Java implementiert wird.

public enum Results { SUCCESS, NOT_READY, THROTTLED, SERVER_ERROR } /* * Performs an asynchronous operation, then polls for the result of the * operation using an incremental delay. */ public static void doOperationAndWaitForResult() { try { // Do some asynchronous operation. long token = asyncOperation(); int retries = 0; boolean retry = false; do { long waitTime = Math.min(getWaitTimeExp(retries), MAX_WAIT_INTERVAL); System.out.print(waitTime + "\n"); // Wait for the result. Thread.sleep(waitTime); // Get the result of the asynchronous operation. Results result = getAsyncOperationResult(token); if (Results.SUCCESS == result) { retry = false; } else if (Results.NOT_READY == result) { retry = true; } else if (Results.THROTTLED == result) { retry = true; } else if (Results.SERVER_ERROR == result) { retry = true; } else { // Some other error occurred, so stop calling the API. retry = false; } } while (retry && (retries++ < MAX_RETRIES)); } catch (Exception ex) { } } /* * Returns the next wait interval, in milliseconds, using an exponential * backoff algorithm. */ public static long getWaitTimeExp(int retryCount) { long waitTime = ((long) Math.pow(2, retryCount) * 100L); return waitTime; }