Die vorliegende Übersetzung wurde maschinell erstellt. Im Falle eines Konflikts oder eines Widerspruchs zwischen dieser übersetzten Fassung und der englischen Fassung (einschließlich infolge von Verzögerungen bei der Übersetzung) ist die englische Fassung maßgeblich.
Amazon QLDB-Treiberempfehlungen
In diesem Abschnitt werden bewährte Methoden zum Konfigurieren und Verwenden des Amazon QLDB-Treibers für jede unterstützte Sprache beschrieben. Bei den Codebeispielen handelt es sich um Java-Beispiele.
Diese Empfehlungen gelten für die meisten typischen Anwendungsfälle, aber nicht für alle. Verwenden Sie die folgenden Empfehlungen, wenn Sie glauben, dass sie für Ihre Anwendung geeignet sind.
Themen
Konfigurieren von QldbDriver Objekt
DieQldbDriver
object verwaltet Verbindungen zu Ihrem Ledger, indem ein Pool vonSitzungendie über Transaktionen hinweg wiederverwendet werden. EINSitzungstellt eine einzelne Verbindung zum Ledger dar. QLDB unterstützt eine aktiv laufende Transaktion pro Sitzung.
Wichtig
Bei älteren Treiberversionen befindet sich die Funktion zum Session-Pooling immer noch imPooledQldbDriver
Objekt anstelle vonQldbDriver
aus. Wenn Sie eine der folgenden Versionen verwenden, ersetzen Sie alle Erwähnungen vonQldbDriver
mitPooledQldbDriver
für den Rest dieses Themas.
Treiber | Version |
---|---|
Java | 1.1.0 oder früher |
.NET | 0.1.0-beta |
Node.js | 1.0.0-rc.1 oder früher |
Python | 2.0.2 oder früher |
DiePooledQldbDriver
-Objekt ist in der neuesten Version der Treiber veraltet. Es wird empfohlen, ein Upgrade auf die neueste Version durchzuführen und alle Instanzen vonPooledQldbDriver
zuQldbDriver
aus.
Konfiguration QldbDriver als globales Objekt
Um die Verwendung von Treibern und Sitzungen zu optimieren, müssen Sie sicherstellen, dass nur eine globale Instance des Treibers in Ihrer Anwendungs-Instance vorhanden ist. In Java können Sie beispielsweise Abhängigkeits-Injection-Frameworks wie SpringQldbDriver
als Singleton konfigurieren.
@Singleton public QldbDriver qldbDriver (AWSCredentialsProvider credentialsProvider, @Named(LEDGER_NAME_CONFIG_PARAM) String ledgerName) { QldbSessionClientBuilder builder = QldbSessionClient.builder(); if (null != credentialsProvider) { builder.credentialsProvider(credentialsProvider); } return QldbDriver.builder() .ledger(ledgerName) .transactionRetryPolicy(RetryPolicy .builder() .maxRetries(3) .build()) .sessionClientBuilder(builder) .build(); }
Konfigurieren der Wiederholungsversuche
Der Treiber wiederholt Transaktionen automatisch, wenn häufige vorübergehende Ausnahmen (z. B.SocketTimeoutException
oderNoHttpResponseException
) treten auf. Um die maximale Anzahl an Wiederholungsversuchen festzulegen, können Sie dasmaxRetries
-Parameter destransactionRetryPolicy
Konfigurationsobjekt beim Erstellen einer Instanz vonQldbDriver
aus. (Verwenden Sie für ältere Treiberversionen, wie im vorherigen Abschnitt aufgeführt,retryLimit
-Parameter vonPooledQldbDriver
.)
Der Standardwert von maxRetries
ist 4
.
Bei clientseitigen Fehlern wie InvalidParameterException
sind keine wiederholten Versuche möglich. Wenn sie auftreten, wird die Transaktion abgebrochen, die Sitzung wird an den Pool zurückgegeben, und eine Ausnahme wird für den Client des Treibers ausgelöst.
Konfigurieren der maximalen Anzahl gleichzeitiger Sitzungen und Transaktionen
Die maximale Anzahl an Ledger-Sitzungen, die von einer Instance vonQldbDriver
Transaktionen auszuführen, wird durch seinemaxConcurrentTransactions
-Parameter. (Für ältere Treiberversionen, wie im vorherigen Abschnitt aufgeführt, wird dies durch diepoolLimit
-Parameter vonPooledQldbDriver
.)
Dieser Grenzwert muss größer als Null und kleiner oder gleich der maximalen Anzahl offener HTTP-Verbindungen sein, die der Sitzungs-Client zulässt (definiert nach Maßgabe des jeweiligenAWS-SDKS. In Java wird die maximale Anzahl an Verbindungen beispielsweise im Objekt ClientConfiguration festgelegt.
Der Standardwert vonmaxConcurrentTransactions
ist die maximale Verbindungseinstellung IhresAWS-SDKS.
Wenn Sie QldbDriver
in der Anwendung konfigurieren, beachten Sie die folgenden Aspekte hinsichtlich der Skalierung:
-
Der Pool sollte immer mindestens so viele Sitzungen enthalten, wie gleichzeitig ausgeführte Transaktionen geplant sind.
-
In einem Multi-Thread-Modell, in dem ein Supervisor-Thread an Worker-Threads delegiert, sollte der Treiber mindestens so viele Sitzungen enthalten, wie Worker-Threads vorliegen. Andernfalls warten Threads bei Spitzenlast nacheinander auf eine verfügbare Sitzung.
-
Das Service-Limit für gleichzeitige aktive Sitzungen pro Ledger ist in Kontingente und Limits in Amazon QLDB definiert. Stellen Sie sicher, dass Sie nicht mehr als dieses Limit an gleichzeitigen Sitzungen für einen einzelnen Ledger über alle Clients konfigurieren.
Erneuter Versuch bei Ausnahmen
Beachten Sie beim erneuten Versuch bei Ausnahmen, die in QLDB auftreten, die folgenden Empfehlungen.
Wiederholen von OccConflictException
Optimistic Concurrency Control(OCC) Konflikte treten auf, wenn sich die Daten, auf die Transaktion zugreift, seit dem Beginn der Transaktion geändert haben. QLDB löst diese Ausnahme aus, während sie versucht, die Transaktion zu übernehmen. Der Fahrer versucht die Transaktion bis zu so oft wiemaxRetries
ist konfiguriert.
Weitere Informationen zu OCC und Best Practices zur Verwendung von Indizes zur Begrenzung von OCC-Konflikten finden Sie unterAmazon QLDB-Nebenläufigkeit von Amazon QLDB-Nebenläufigkeitaus.
Andere Ausnahmen außerhalb von QlDbDriver erneut versuchen
Um eine Transaktion außerhalb des Treibers zu wiederholen, wenn benutzerdefinierte, anwendungsdefinierte Ausnahmen während der Laufzeit ausgelöst werden, müssen Sie die Transaktion umbrechen. Der folgende Code zeigt beispielsweise, wie Sie dasReslience4J
private final RetryConfig retryConfig = RetryConfig.custom() .maxAttempts(MAX_RETRIES) .intervalFunction(IntervalFunction.ofExponentialRandomBackoff()) // Retry this exception .retryExceptions(InvalidSessionException.class, MyRetryableException.class) // But fail for any other type of exception extended from RuntimeException .ignoreExceptions(RuntimeException.class) .build(); // Method callable by a client public void myTransactionWithRetries(Params params) { Retry retry = Retry.of("registerDriver", retryConfig); Function<Params, Void> transactionFunction = Retry.decorateFunction( retry, parameters -> transactionNoReturn(params)); transactionFunction.apply(params); } private Void transactionNoReturn(Params params) { try (driver.execute(txn -> { // Transaction code }); } return null; }
Anmerkung
Das erneute Versuch einer Transaktion außerhalb des QLDB-Treibers hat einen Multiplikatoreffekt. Zum Beispiel, wennQldbDriver
ist so konfiguriert, dass drei Wiederholungen versucht werden, und die benutzerdefinierte Wiederholungslogik wiederholt sich ebenfalls drei Wiederholungen, dieselbe Transaktion kann bis zu neun Mal wiederholt werden.
Transaktionen idempotent machen
Als bewährte Methode sollten Sie Ihre Schreibtransaktionen idempotent machen, um unerwartete Nebenwirkungen im Falle von Wiederholungen zu vermeiden. Eine Transaktion istidempotentwenn es mehrmals laufen kann und jedes Mal identische Ergebnisse erzielen kann.
Weitere Informationen hierzu finden Sie unter Amazon QLDB-Nebenläufigkeit von Amazon QLDB-Nebenläufigkeit.
Optimierung der Leistung
Um die Leistung beim Ausführen von Transaktionen mit dem Treiber zu optimieren, sollten Sie Folgendes berücksichtigen:
-
Die
execute
Betrieb macht immer mindestens dreiSendCommand
-Aufrufe der API an QLDB, die folgende Befehle enthalten:-
StartTransaction
-
ExecuteStatement
Dieser Befehl wird für jede PartiQL-Anweisung aufgerufen, die Sie im
execute
blockieren. -
CommitTransaction
Berücksichtigen Sie die Gesamtzahl der auszuführenden API-Aufrufe, wenn Sie die Gesamt-Workload der Anwendung kalkulieren.
-
-
Grundsätzlich empfehlen wir, mit einem Single-Thread-Writer zu beginnen und Transaktionen zu optimieren, indem mehrere Anweisungen in einer Transaktion zusammengefasst werden. Maximieren Sie die Kontingente für Transaktionsgröße, Dokumentgröße und Anzahl der Dokumente pro Transaktion gemäß der Definition in Kontingente und Limits in Amazon QLDB.
-
Wenn das Batching für große Transaktionslasten nicht ausreicht, können Sie es mit Multi-Threading versuchen, indem Sie weitere Writer hinzufügen. Sie sollten jedoch sorgfältig die Anwendungsanforderungen an die Dokument- und Transaktionssequenzierung im Hinblick auf die damit einhergehende Komplexität abwägen.
Ausführen mehrerer Anweisungen pro Transaktion
Wie in dervorheriger Abschnitt, können Sie mehrere Anweisungen pro Transaktion ausführen, um die Leistung Ihrer Anwendung zu optimieren. Im folgenden Codebeispiel fragen Sie eine Tabelle ab und aktualisieren dann ein Dokument in dieser Tabelle innerhalb einer Transaktion. Hierzu übergeben Sie einen Lambda-Ausdruck anexecute
verwenden.
Die des Fahrersexecute
-Operation startet implizit eine Sitzung und eine Transaktion in dieser Sitzung. Jede Anweisung, die Sie im Lambda-Ausdruck ausführen, wird in die Transaktion eingeschlossen. Nachdem alle Anweisungen ausgeführt wurden, schreibt der Treiber die Transaktion automatisch fest. Wenn eine Anweisung fehlschlägt, nachdem das automatische Wiederholungslimit erschöpft ist, wird die Transaktion abgebrochen.
Verbreiten von Ausnahmeregelungen in einer Transaktion
Wenn Sie mehrere Anweisungen pro Transaktion ausführen, empfehlen wir im Allgemeinen nicht, dass Sie Ausnahmen innerhalb der Transaktion abfangen und übergeben.
Beispielsweise fängt das folgende Programm in Java jede Instance von RuntimeException
ab, protokolliert den Fehler und fährt fort. Dieses Codebeispiel wird als schlechte Praxis angesehen, da die Transaktion sogar dann erfolgreich ist, wenn die UPDATE
-Anweisung fehlschlägt. Daher geht der Client möglicherweise davon aus, dass das Update erfolgreich war, auch dies nicht der Fall war.
Warnung
Verwenden Sie nicht dieses Codebeispiel. Er wird bereitgestellt, um ein Anti-Pattern-Beispiel zu zeigen, das als schlechte Praxis gilt.
// DO NOT USE this code example because it is considered bad practice
public static void main(final String... args) {
ConnectToLedger.getDriver().execute(txn -> {
final Result selectTableResult = txn.execute("SELECT * FROM Vehicle WHERE VIN ='123456789'");
// Catching an error inside the transaction is an anti-pattern because the operation might
// not succeed.
// In this example, the transaction succeeds even when the update statement fails.
// So, the client might assume that the update succeeded when it didn't.
try {
processResults(selectTableResult);
String model = // some code that extracts the model
final Result updateResult = txn.execute("UPDATE Vehicle SET model = ? WHERE VIN = '123456789'",
Constants.MAPPER.writeValueAsIonValue(model));
} catch (RuntimeException e) {
log.error("Exception when updating the Vehicle table {}", e.getMessage());
}
});
log.info("Vehicle table updated successfully.");
}
Propagiere stattdessen die Ausnahme (sprenge nach oben). Wenn ein Teil der Transaktion fehlschlägt, lassen Sieexecute
bricht die Transaktion ab, damit der Kunde die Ausnahme entsprechend behandeln kann.