Las traducciones son generadas a través de traducción automática. En caso de conflicto entre la traducción y la version original de inglés, prevalecerá la version en inglés.
Recomendaciones de QLDB conductores de Amazon
importante
Aviso de fin del soporte: los clientes actuales podrán utilizar Amazon QLDB hasta que finalice el soporte, el 31 de julio de 2025. Para obtener más información, consulte Migración de un Amazon QLDB Ledger a Amazon Aurora SQL Postgre
En esta sección se describen las prácticas recomendadas para configurar y usar el QLDB controlador de Amazon para cualquier idioma compatible. Los ejemplos de código proporcionados son específicos para Java.
Estas recomendaciones se aplican a la mayoría de los casos de uso típicos, pero no hay una solución única para todos. Utilice las siguientes recomendaciones como mejor le parezca para su aplicación.
Temas
Configurar el QldbDriver objeto
El objeto QldbDriver
administras las conexiones a su libro mayor manteniendo un conjunto de sesiones que se reutilizan en todas las transacciones. Una sesión representa una conexión única con el libro mayor. QLDBadmite una transacción en ejecución activa por sesión.
importante
En las versiones anteriores del controlador, la funcionalidad de agrupación de sesiones sigue estando en el objeto PooledQldbDriver
y no en QldbDriver
. Si utiliza una de las siguientes versiones, sustituya cualquier mención de QldbDriver
por PooledQldbDriver
para el resto de este tema.
Controlador | Versión |
---|---|
Java | 1.1.0 o anterior |
.NET | 0.1.0-beta |
Node.js | 1.0.0-rc.1 o anterior |
Python | 2.0.2 o anterior |
El objeto PooledQldbDriver
está obsoleto en la versión más reciente de los controladores. Se recomienda actualizar a la versión más reciente y convertir cualquier instancia de PooledQldbDriver
a QldbDriver
.
QldbDriver Configúralo como un objeto global
Para optimizar el uso de los controladores y las sesiones, asegúrese de que solo exista una instancia global del controlador en la instancia de la aplicación. Por ejemplo, en Java, puede usar marcos de inyección de dependencias como SpringQldbDriver
como 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(); }
Configuración de los reintentos
El controlador vuelve a intentar las transacciones automáticamente cuando se producen excepciones transitorias comunes (por ejemplo, SocketTimeoutException
o NoHttpResponseException
). Para establecer el número máximo de reintentos, puede utilizar el parámetro maxRetries
del objeto de configuración transactionRetryPolicy
al crear una instancia de QldbDriver
. (Para versiones anteriores del controlador, como se indica en la sección anterior, utilice el parámetro retryLimit
de PooledQldbDriver
.)
El valor predeterminado de maxRetries
es 4
.
Errores del cliente, como InvalidParameterException
no se pueden volver a intentar. Cuando se producen, la transacción se cancela, la sesión se devuelve al grupo y la excepción se envía al cliente del controlador.
Configuración del número máximo de sesiones y transacciones simultáneas
El número máximo de sesiones de libro mayor que utiliza una instancia QldbDriver
para ejecutar transacciones viene definido por su parámetro maxConcurrentTransactions
. (Para versiones anteriores del controlador, como se indica en la sección anterior, se define en el parámetro poolLimit
de PooledQldbDriver
.)
Este límite debe ser superior a cero e inferior o igual al número máximo de HTTP conexiones abiertas que permite el cliente de sesión, según lo defina la especificación AWS SDK. Por ejemplo, en Java, el número máximo de conexiones se establece en el ClientConfigurationobjeto.
El valor predeterminado de maxConcurrentTransactions
es la configuración de conexión máxima de su AWS SDK.
Cuando configure QldbDriver
en su aplicación, tenga en cuenta las siguientes consideraciones de escalado:
-
Su grupo siempre debe tener al menos tantas sesiones como el número de transacciones en ejecución simultánea que planea tener.
-
En un modelo de subprocesos múltiples en el que un subproceso supervisor delega en subprocesos de trabajo, el controlador debe tener al menos tantas sesiones como el número de subprocesos de trabajo. De lo contrario, en el momento de máxima carga, los subprocesos estarán esperando en fila hasta que haya una sesión disponible.
-
El límite de servicio de sesiones activas simultáneas por libro mayor se define en Cuotas y límites en Amazon QLDB. Asegúrese de no haber configurado un número de sesiones simultáneas superior a este límite para utilizarlas en un solo libro mayor en todos los clientes.
Reintentar en caso de excepciones
Cuando vuelva a intentarlo con las excepciones que se produzcan enQLDB, tenga en cuenta las siguientes recomendaciones.
Intentándolo de nuevo OccConflictException
Las excepciones de conflicto del control de simultaneidad optimista (OCC) se producen cuando los datos a los que accede la transacción han cambiado desde el inicio de la transacción. QLDBlanza esta excepción al intentar confirmar la transacción. El controlador vuelve a intentar la transacción tantas veces como se haya configurado en maxRetries
.
Para obtener más información sobre el uso de índices OCC y las prácticas recomendadas para limitar OCC los conflictos, consulteModelo de QLDB simultaneidad de Amazon.
Volver a intentarlo con otras excepciones fuera de QldbDriver
Para reintentar una transacción fuera del controlador cuando se producen excepciones personalizadas y definidas por la aplicación durante el tiempo de ejecución, debe empaquetar la transacción. Por ejemplo, en Java, el código siguiente muestra cómo utilizar la biblioteca Reslience4J
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; }
nota
Reintentar una transacción fuera del controlador tiene un efecto multiplicadorQLDB. Por ejemplo, si QldbDriver
está configurado para volver a intentarlo tres veces y la lógica de reintento personalizada también lo hace tres veces, se puede volver a intentar la misma transacción hasta nueve veces.
Hacer que las transacciones sean idempotentes
Como práctica recomendada, haga que sus transacciones de escritura sean idempotentes para evitar cualquier efecto secundario inesperado en caso de reintentos. Una transacción es idempotente si puede ejecutarse varias veces y producir resultados idénticos cada vez.
Para obtener más información, consulte Modelo de QLDB simultaneidad de Amazon.
Optimización del rendimiento
Para optimizar el rendimiento al ejecutar transacciones con el controlador, tenga en cuenta las siguientes consideraciones:
-
La
execute
operación siempre realiza un mínimo de tresSendCommand
API llamadas aQLDB, incluidos los siguientes comandos:-
StartTransaction
-
ExecuteStatement
Este comando se invoca para cada instrucción PartiQL que ejecute en el bloque
execute
. -
CommitTransaction
Tenga en cuenta el número total de API llamadas que se realizan al calcular la carga de trabajo total de la aplicación.
-
-
En general, se recomienda empezar con un escritor de un solo subproceso y optimizar las transacciones agrupando varias instrucciones en una sola transacción. Maximice las cuotas de tamaño de transacción, tamaño de documento y cantidad de documentos por transacción, tal y como se define en Cuotas y límites en Amazon QLDB.
-
Si el procesamiento por lotes no es suficiente para grandes cargas de transacciones, puede probar con varios subprocesos añadiendo instancias de escritura adicionales. Sin embargo, debe considerar detenidamente los requisitos de su solicitud para la secuenciación de documentos y transacciones y la complejidad adicional que esto implica.
Ejecutar varias instrucciones por transacción
Como se describe en la sección anterior, puede ejecutar varias instrucciones por transacción para optimizar el rendimiento de su aplicación. En el siguiente ejemplo de código, se consulta una tabla y, a continuación, se actualiza un documento de esa tabla dentro de una transacción. Para ello, debe pasar una expresión lambda a la operación execute
.
La operación execute
del controlador inicia implícitamente una sesión y una transacción en esa sesión. Cada instrucción que se ejecuta en la expresión lambda se incluye en la transacción. Una vez ejecutadas todas las instrucciones, el controlador confirma automáticamente la transacción. Si alguna instrucción falla una vez agotado el límite de reintentos automáticos, la transacción se cancela.
Propagar las excepciones en una transacción
Cuando se ejecutan varias instrucciones por transacción, por lo general, no recomendamos detectar excepciones dentro de la transacción.
Por ejemplo, en Java, el siguiente programa detecta cualquier instancia de RuntimeException
, registra el error y continúa. Este ejemplo de código se considera una mala práctica porque la transacción se realiza correctamente incluso cuando la instrucción UPDATE
falla. Por lo tanto, el cliente podría suponer que la actualización se realizó correctamente, pero no fue así.
aviso
No utilice este ejemplo de código. Se proporciona para mostrar un ejemplo anti-patrón que se considera una mala práctica.
// 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.");
}
En su lugar, propague (haga crecer) la excepción. Si alguna parte de la transacción falla, deje que la operación execute
cancele la transacción para que el cliente pueda gestionar la excepción en consecuencia.