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.
Verrouillage distribué avec le client DynamoDB Lock
Pour les applications qui nécessitent une lock-acquire-release sémantique traditionnelle, le client DynamoDB Lock est une bibliothèque open source qui implémente le verrouillage distribué en utilisant une table DynamoDB comme magasin de verrous. Cette approche est utile lorsque vous devez coordonner l'accès à une ressource externe (telle qu'un objet S3 ou une configuration partagée) entre plusieurs instances d'application.
Le client de verrouillage est disponible sous forme de bibliothèque Java
Comment ça marche
Le client de verrouillage utilise une table DynamoDB dédiée pour suivre les verrouillages. Chaque verrou est représenté sous la forme d'un élément doté des attributs clés suivants :
Clé de partition qui identifie la ressource verrouillée.
Durée du bail qui indique la durée de validité du verrou. Si le porte-cadenas tombe en panne ou ne répond plus, le verrou expire automatiquement après la durée du bail.
Un battement de cœur que le porteur du cadenas envoie périodiquement pour prolonger le bail. Cela empêche le verrou d'expirer alors que le support est encore en cours de traitement.
Le client de verrouillage utilise des écritures conditionnelles pour garantir qu'un seul processus peut acquérir un verrou à la fois. Si un verrou est déjà bloqué, l'appelant peut choisir d'attendre et de réessayer ou d'échouer immédiatement.
Quand utiliser le client de verrouillage
Le client de verrouillage convient parfaitement lorsque :
Vous devez coordonner l'accès à une ressource partagée entre plusieurs instances d'application ou microservices.
La section critique est longue (quelques secondes à quelques minutes) et il serait coûteux de réessayer l'ensemble de l'opération en cas de conflit.
Vous avez besoin d'une expiration automatique du verrouillage pour gérer les défaillances de processus avec élégance.
Les exemples courants incluent l'orchestration de flux de travail distribués, la coordination des tâches cron sur plusieurs instances et la gestion de l'accès aux ressources externes partagées.
Compromis
- Infrastructure supplémentaire
Nécessite une table DynamoDB dédiée pour la gestion du verrouillage, avec une capacité de lecture et d'écriture supplémentaire pour les opérations de verrouillage et les pulsations cardiaques.
- Dépendance d'horloge
L'expiration du verrou dépend de l'horodatage. Un décalage horaire important entre les clients peut entraîner un comportement inattendu, en particulier pour les courtes durées de location.
- Risque de blocage
Si votre application obtient des verrous sur plusieurs ressources, vous devez les verrouiller dans un ordre cohérent pour éviter les blocages. La durée du bail constitue un filet de sécurité en déverrouillant automatiquement les serrures lorsque les détenteurs ne répondent pas.
Mise en œuvre
L'exemple suivant montre comment utiliser le client DynamoDB Lock pour acquérir et libérer un verrou :
import java.io.IOException; import java.util.Optional; import java.util.concurrent.TimeUnit; import software.amazon.awssdk.services.dynamodb.DynamoDbClient; final DynamoDbClient dynamoDB = DynamoDbClient.builder() .region(Region.US_WEST_2) .build(); final AmazonDynamoDBLockClient lockClient = new AmazonDynamoDBLockClient( AmazonDynamoDBLockClientOptions.builder(dynamoDB, "Locks") .withTimeUnit(TimeUnit.SECONDS) .withLeaseDuration(10L) .withHeartbeatPeriod(3L) .withCreateHeartbeatBackgroundThread(true) .build()); // Try to acquire a lock on a resource final Optional<LockItem> lock = lockClient.tryAcquireLock(AcquireLockOptions.builder("my-shared-resource").build()); if (lock.isPresent()) { try { // Perform operations that require exclusive access processSharedResource(); } finally { // Always release the lock when done lockClient.releaseLock(lock.get()); } } else { System.out.println("Failed to acquire lock."); } lockClient.close();
Important
Relâchez toujours les verrous d'un finally bloc pour vous assurer que les verrous sont libérés même si votre logique de traitement génère une exception. Les verrous inédits bloquent les autres processus jusqu'à l'expiration du bail.
Vous pouvez également implémenter un mécanisme de verrouillage simple sans verrouiller la bibliothèque cliente en utilisant directement les écritures conditionnelles. L'exemple suivant utilise UpdateItem une expression de condition pour acquérir un verrou et DeleteItem le libérer :
from datetime import datetime, timedelta from boto3.dynamodb.conditions import Attr def acquire_lock(table, resource_name, owner_id, ttl_seconds): """Attempt to acquire a lock. Returns True if successful.""" expiry = (datetime.now() + timedelta(seconds=ttl_seconds)).isoformat() now = datetime.now().isoformat() try: table.update_item( Key={'LockID': resource_name}, UpdateExpression='SET #owner = :owner, #expiry = :expiry', ConditionExpression=Attr('LockID').not_exists() | Attr('ExpiresAt').lt(now), ExpressionAttributeNames={'#owner': 'OwnerID', '#expiry': 'ExpiresAt'}, ExpressionAttributeValues={':owner': owner_id, ':expiry': expiry} ) return True except table.meta.client.exceptions.ConditionalCheckFailedException: return False def release_lock(table, resource_name, owner_id): """Release a lock. Only succeeds if the caller is the lock owner.""" try: table.delete_item( Key={'LockID': resource_name}, ConditionExpression=Attr('OwnerID').eq(owner_id) ) return True except table.meta.client.exceptions.ConditionalCheckFailedException: return False
Cette approche utilise une expression conditionnelle pour garantir qu'un verrou ne peut être acquis que s'il n'existe pas ou a expiré, et qu'il ne peut être libéré que par le processus qui l'a acquis. Envisagez d'activer le délai de vie (TTL) sur la table de verrouillage pour nettoyer automatiquement les éléments de verrouillage expirés.