Les traductions sont fournies par des outils de traduction automatique. En cas de conflit entre le contenu d'une traduction et celui de la version originale en anglais, la version anglaise prévaudra.
Recommandations de pilotes Amazon QLDB
Cette section décrit les meilleures pratiques de configuration et d'utilisation du pilote Amazon QLDB pour n'importe quelle langue prise en charge. Les exemples de code fournis concernent spécifiquement Java.
Ces recommandations s'appliquent à la plupart des cas d'utilisation courants, mais une taille unique ne convient pas à tous. Utilisez les recommandations suivantes comme bon vous semble approprié pour votre application.
Rubriques
Configuration de QldbDriver objet
LeQldbDriver
gère les connexions à votre livre en maintenant un pool desessionsqui sont réutilisés dans toutes les transactions. UNsessionreprésente une connexion unique au grand livre. QLDB prend en charge une transaction active par session.
Important
Pour les anciennes versions de pilotes, la fonctionnalité de pool de sessions se trouve toujours dans lePooledQldbDriver
objet et non deQldbDriver
. Si vous utilisez l'une des versions suivantes, remplacez toutes les mentions deQldbDriver
avecPooledQldbDriver
pour le reste de ce sujet.
Pilote | Version |
---|---|
Java | 1.1.0 ou antérieures |
.NET | 0.1.0-beta |
Node.js | 1.0.0-rc.1 ou antérieures |
Python | 2.0.2 ou antérieures |
LePooledQldbDriver
l'objet est obsolète dans la dernière version des pilotes. Nous vous recommandons de procéder à une mise à niveau vers la dernière version et de convertir toutes les instances dePooledQldbDriver
pourQldbDriver
.
Configuration QldbDriver en tant qu'objet global
Pour optimiser l'utilisation des pilotes et des sessions, assurez-vous qu'une seule instance globale du pilote existe dans votre instance d'application. Par exemple, en Java, vous pouvez utiliserInjection de dépendanceframeworks tels quePrintempsQldbDriver
en singleton.
@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(); }
Configurer les tentatives de nouvelle tentative
Le pilote retente automatiquement les transactions lorsque des exceptions transitoires courantes (telles queSocketTimeoutException
ouNoHttpResponseException
) se produisent. Pour définir le nombre maximal de nouvelles tentatives, vous pouvez utiliser l'optionmaxRetries
paramètre de latransactionRetryPolicy
objet de configuration lors de la création d'une instance deQldbDriver
. (Pour les anciennes versions de pilotes répertoriées dans la section précédente, utilisez leretryLimit
paramètre dePooledQldbDriver
.)
La valeur par défaut de maxRetries
est 4
.
Erreurs côté du client, telles queInvalidParameterException
ne peut pas être réessayé. Lorsqu'elles se produisent, la transaction est interrompue, la session est renvoyée au pool et l'exception est renvoyée au client du pilote.
Configuration du nombre maximal de sessions et de transactions simultanées
Le nombre maximal de sessions de livres utilisées par une instance deQldbDriver
pour exécuter des transactions est défini par sonmaxConcurrentTransactions
Paramètre . (Pour les anciennes versions de pilotes répertoriées dans la section précédente, cela est défini par lepoolLimit
paramètre dePooledQldbDriver
.)
Cette limite doit être supérieure à zéro et inférieure ou égale au nombre maximal de connexions HTTP ouvertes que le client de session autorise, tel que défini par le paramètre spécifique.AWSSDK. Par exemple, en Java, le nombre maximal de connexions est défini dans leClientConfigurationobjet.
La valeur par défaut demaxConcurrentTransactions
est le paramètre de connexion maximal de votreAWSSDK.
Lorsque vous configurez leQldbDriver
dans votre application, prenez en compte les considérations de dimensionnement suivantes :
-
Votre pool doit toujours avoir au moins autant de sessions que le nombre de transactions exécutées simultanément que vous prévoyez d'avoir.
-
Dans un modèle multithread où un thread de superviseur délègue à des threads de travail, le pilote doit avoir au moins autant de sessions que le nombre de threads de travail. Sinon, à la charge maximale, les threads seront en attente d'une session disponible.
-
La limite de service des sessions actives simultanées par livre est définie dansQuotas et limites d'Amazon QLDB. Assurez-vous que vous ne configurez pas plus que cette limite de sessions simultanées pour être utilisées pour un seul livre sur tous les clients.
Nouvelles tentatives en cas d'exception
Lorsque vous tentez de nouveau les exceptions qui se produisent dans QLDB, tenez compte des recommandations suivantes.
Nouvelles tentatives d'exception OccConflictException
Contrôle optimiste de la concurrenceLes exceptions de conflit (OCC) se produisent lorsque les données auxquelles la transaction accède ont changé depuis le début de la transaction. QLDB lance cette exception en essayant de valider la transaction. Le conducteur retente la transaction jusqu'à autant de fois quemaxRetries
est configuré.
Pour plus d'informations sur OCC et sur les meilleures pratiques d'utilisation des index pour limiter les conflits OCC, voirModèle de mise QLDB simultansimultansimultansimultansimultansimultansimultansimultansimultanéité.
Réessayer d'autres exceptions en dehors de QLDBDriver
Pour réessayer une transaction en dehors du pilote lorsque des exceptions personnalisées définies par l'application sont lancées pendant l'exécution, vous devez encapsuler la transaction. Par exemple, en Java, le code suivant montre comment utiliser l'optionRélience 4J
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; }
Note
La nouvelle tentative d'une transaction en dehors du pilote QLDB a un effet multiplicateur. Par exemple, siQldbDriver
est configuré pour réessayer trois fois, et la logique de nouvelle tentative personnalisée à nouveau trois fois, la même transaction peut être retentée jusqu'à neuf fois.
Indempotence des transactions
Comme meilleure pratique, rendez vos transactions d'écriture idépotentes afin d'éviter tout effet secondaire inattendu en cas de nouvelles tentatives. Une transaction estidempotentss'il peut s'exécuter plusieurs fois et produire des résultats identiques à chaque fois.
Pour en savoir plus, veuillez consulter la section Modèle de mise QLDB simultansimultansimultansimultansimultansimultansimultansimultansimultanéité.
Optimisation des performances
Pour optimiser les performances lorsque vous exécutez des transactions à l'aide du pilote, tenez compte des considérations suivantes :
-
Le
execute
l'opération fait toujours un minimum de troisSendCommand
Appels API vers QLDB, y compris les commandes suivantes :-
StartTransaction
-
ExecuteStatement
Cette commande est appelée pour chaque instruction PartiQL que vous exécutez dans le
execute
block. -
CommitTransaction
Tenez compte du nombre total d'appels d'API effectués lorsque vous calculez la charge de travail globale de votre application.
-
-
En général, nous recommandons de commencer par un graveur monothread et d'optimiser les transactions en regroupant plusieurs instructions au sein d'une seule transaction. Maximisez les quotas sur la taille des transactions, la taille du document et le nombre de documents par transaction, comme défini dansQuotas et limites d'Amazon QLDB.
-
Si le traitement par lots n'est pas suffisant pour les charges de transactions volumineuses, vous pouvez essayer le multithreading en ajoutant des rédacteurs supplémentaires. Toutefois, vous devez examiner attentivement les exigences de votre application pour le séquençage des documents et des transactions, ainsi que la complexité supplémentaire que cela introduit.
Exécution de plusieurs instructions par transaction
Comme décrit dans lasection précédente, vous pouvez exécuter plusieurs relevés par transaction pour optimiser les performances de votre application. Dans l'exemple de code suivant, vous interrogez une table, puis mettez à jour un document de cette table dans une transaction. Pour ce faire, vous transmettez une expression lambda à laexecute
.
Le chauffeurexecute
l'opération démarre implicitement une session et une transaction dans cette session. Chaque instruction que vous exécutez dans l'expression lambda est encapsulée dans la transaction. Une fois toutes les instructions exécutées, le pilote valide automatiquement la transaction. Si une instruction échoue après que la limite de nouvelle tentative automatique est épuisée, la transaction est interrompue.
Propager les exceptions dans une transaction
Lorsque vous exécutez plusieurs instructions par transaction, nous ne recommandons généralement pas d'catch et d'avaler des exceptions au sein de la transaction.
Par exemple, en Java, le programme suivant capture n'importe quelle instance deRuntimeException
, enregistre l'erreur et continue. Cet exemple de code est considéré comme une mauvaise pratique car la transaction réussit même lorsque leUPDATE
l'instruction échoue. Par conséquent, le client peut supposer que la mise à jour a réussi alors que ce n'est pas le cas.
Avertissement
N'utilisez pas cet exemple de code. Il est fourni pour montrer un exemple anti-pattern considéré comme une mauvaise pratique.
// 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.");
}
Propagez plutôt l'exception (bulle vers le haut). Si une partie de la transaction échoue, laissez leexecute
l'opération interrompt la transaction afin que le client puisse gérer l'exception en conséquence.