Tutorial: creazione di tabelle globali - Amazon DynamoDB

Le traduzioni sono generate tramite traduzione automatica. In caso di conflitto tra il contenuto di una traduzione e la versione originale in Inglese, quest'ultima prevarrà.

Tutorial: creazione di tabelle globali

Questa sezione fornisce step-by-step istruzioni per creare tabelle globali DynamoDB configurate per la modalità di consistenza preferita. Seleziona la modalità a coerenza finale multi-Regione (MREC, Multi-Region Eventual Consistency) o elevata consistenza multi-Regione (MRSC, Multi-Region Strong Consistency) in base ai requisiti dell’applicazione.

Le tabelle globali MREC offrono una latenza di scrittura inferiore con una coerenza finale generale Regioni AWS. Le tabelle globali MRSC forniscono operazioni a elevata consistenza di lettura tra le Regioni con latenze di scrittura leggermente superiori rispetto a MREC. Sceglie la modalità di coerenza che meglio soddisfa le esigenze dell’applicazione in termini di coerenza, latenza e disponibilità dei dati.

Creazione di una tabella globale configurata per MREC

Questa sezione mostra come creare una tabella globale con la modalità a coerenza finale multi-Regione (MREC). MREC è la modalità di coerenza predefinita per le tabelle globali e fornisce scritture a bassa latenza con replica asincrona su tutte le Regioni AWS. Le modifiche apportate a un elemento in una Regione vengono in genere replicate in tutte le altre Regioni entro un secondo. Ciò rende la MREC ideale per le applicazioni che danno priorità a una bassa latenza di scrittura e possono tollerare brevi periodi in cui Regioni diverse possono restituire versioni di dati leggermente diverse.

È possibile creare tabelle globali MREC con repliche in qualsiasi regione in AWS cui è disponibile DynamoDB e aggiungere o rimuovere repliche in qualsiasi momento. Gli esempi seguenti mostrano come creare una tabella globale MREC con repliche in più Regioni.

Completa questa procedura per creare una tabella globale utilizzando Console di gestione AWS. Il seguente esempio consente di creare una tabella globale con le tabelle di replica negli Stati Uniti e in Europa.

  1. Accedi Console di gestione AWS e apri la console DynamoDB all'indirizzo. https://console.aws.amazon.com/dynamodb/

  2. Per questo esempio, seleziona Stati Uniti orientali (Ohio) dal selettore delle Regioni nella barra di navigazione.

  3. Nel riquadro di navigazione sul lato sinistro della console scegli Tables (Tabelle).

  4. Scegliere Create Table (Crea tabella).

  5. Nella pagina Crea tabella:

    1. Nel campo Table name (Nome tabella) immetti Music.

    2. In Partition key (Chiave di partizione), inserisci Artist.

    3. Per Chiave di ordinamento, immetti SongTitle.

    4. Mantieni le restanti impostazioni predefinite e seleziona Crea tabella.

      Questa nuova tabella funge da prima tabella di replica in una nuova tabella globale. È il prototipo per altre tabelle di replica che verranno aggiunte in seguito.

  6. Dopo che la tabella è diventata attiva:

    1. Nell’elenco delle tabelle, seleziona la tabella Musica.

    2. Seleziona la scheda Tabelle globali.

    3. Scegliere Crea replica.

  7. Dall’elenco a discesa Regioni di replica disponibili, seleziona Stati Uniti occidentali (Oregon) us-west-2.

    La console verifica che non esista una tabella con lo stesso nome nella Regione selezionata. Se esiste una tabella con lo stesso nome, è necessario eliminare la tabella esistente prima di poter creare una nuova tabella di replica in quella regione.

  8. Scegliere Crea replica. Viene avviato il processo di creazione della tabella nella Regione Stati Uniti occidentali (Oregon) us-west-2.

    La scheda Tabelle globali per la tabella Musica (e per qualsiasi altra tabella di replica) mostra che la tabella è stata replicata in più Regioni.

  9. Aggiungi un’altra Regione ripetendo le fasi precedenti, ma seleziona Europa (Francoforte) eu-central-1 come Regione.

  10. Per testare la replica:

    1. Assicurati di utilizzare la Console di gestione AWS regione Stati Uniti orientali (Ohio).

    2. Scegli Explore table items (Esplora elementi della tabella).

    3. Scegli Crea elemento.

    4. Entra item_1 per Artista e Song Value 1 per SongTitle.

    5. Scegli Crea elemento.

  11. Verifica la replica passando alle altre Regioni:

    1. Dal selettore delle Regioni in alto a destra, seleziona Europa (Francoforte).

    2. Verifica che la tabella Musica contenga l’elemento creato.

    3. Ripeti la verifica per Stati Uniti occidentali (Oregon).

CLI

Nell’esempio di codice seguente viene mostrato come creare e gestire le tabelle globali DynamoDB con replica multi-Regione con coerenza possibile (MREC).

  • Creazione di una tabella con replica multi-Regione (MREC).

  • Inserimento e recupero di elementi dalle tabelle di replica.

  • Rimuovi le repliche. one-by-one

  • Per eseguire la pulizia mediante l’eliminazione delle tabelle.

AWS CLI con lo script Bash

Per creare una tabella con replica multi-Regione.

# Step 1: Create a new table (MusicTable) in US East (Ohio), with DynamoDB Streams enabled (NEW_AND_OLD_IMAGES) aws dynamodb create-table \ --table-name MusicTable \ --attribute-definitions \ AttributeName=Artist,AttributeType=S \ AttributeName=SongTitle,AttributeType=S \ --key-schema \ AttributeName=Artist,KeyType=HASH \ AttributeName=SongTitle,KeyType=RANGE \ --billing-mode PAY_PER_REQUEST \ --stream-specification StreamEnabled=true,StreamViewType=NEW_AND_OLD_IMAGES \ --region us-east-2 # Step 2: Create an identical MusicTable table in US East (N. Virginia) aws dynamodb update-table --table-name MusicTable --cli-input-json \ '{ "ReplicaUpdates": [ { "Create": { "RegionName": "us-east-1" } } ] }' \ --region us-east-2 # Step 3: Create a table in Europe (Ireland) aws dynamodb update-table --table-name MusicTable --cli-input-json \ '{ "ReplicaUpdates": [ { "Create": { "RegionName": "eu-west-1" } } ] }' \ --region us-east-2

Per descrivere la tabella multi-Regione.

# Step 4: View the list of replicas created using describe-table aws dynamodb describe-table \ --table-name MusicTable \ --region us-east-2 \ --query 'Table.{TableName:TableName,TableStatus:TableStatus,MultiRegionConsistency:MultiRegionConsistency,Replicas:Replicas[*].{Region:RegionName,Status:ReplicaStatus}}'

Per inserire elementi in una tabella di replica.

# Step 5: To verify that replication is working, add a new item to the Music table in US East (Ohio) aws dynamodb put-item \ --table-name MusicTable \ --item '{"Artist": {"S":"item_1"},"SongTitle": {"S":"Song Value 1"}}' \ --region us-east-2

Per ottenere elementi dalle tabelle di replica.

# Step 6: Wait for a few seconds, and then check to see whether the item has been # successfully replicated to US East (N. Virginia) and Europe (Ireland) aws dynamodb get-item \ --table-name MusicTable \ --key '{"Artist": {"S":"item_1"},"SongTitle": {"S":"Song Value 1"}}' \ --region us-east-1 aws dynamodb get-item \ --table-name MusicTable \ --key '{"Artist": {"S":"item_1"},"SongTitle": {"S":"Song Value 1"}}' \ --region eu-west-1

Per rimuovere le repliche.

# Step 7: Delete the replica table in Europe (Ireland) Region aws dynamodb update-table --table-name MusicTable --cli-input-json \ '{ "ReplicaUpdates": [ { "Delete": { "RegionName": "eu-west-1" } } ] }' \ --region us-east-2 # Delete the replica table in US East (N. Virginia) Region aws dynamodb update-table --table-name MusicTable --cli-input-json \ '{ "ReplicaUpdates": [ { "Delete": { "RegionName": "us-east-1" } } ] }' \ --region us-east-2

Per eseguire la pulizia mediante l’eliminazione delle tabelle.

# Clean up: Delete the primary table aws dynamodb delete-table --table-name MusicTable --region us-east-2 echo "Global table demonstration complete."
Java

L’esempio di codice seguente mostra come creare e gestire tabelle globali DynamoDB con repliche tra più Regioni.

  • Crea una tabella con Global Secondary Index e DynamoDB Streams.

  • Aggiunta di repliche in Regioni diverse per creare una tabella globale.

  • Rimuovi le repliche da una tabella globale.

  • Aggiungi elementi di test per verificare la replica tra le regioni.

  • Descrivi la configurazione globale della tabella e lo stato della replica.

SDK per Java 2.x

Crea una tabella con Global Secondary Index e DynamoDB Streams utilizzando. AWS SDK for Java 2.x

public static CreateTableResponse createTableWithGSI( final DynamoDbClient dynamoDbClient, final String tableName, final String indexName) { if (dynamoDbClient == null) { throw new IllegalArgumentException("DynamoDB client cannot be null"); } if (tableName == null || tableName.trim().isEmpty()) { throw new IllegalArgumentException("Table name cannot be null or empty"); } if (indexName == null || indexName.trim().isEmpty()) { throw new IllegalArgumentException("Index name cannot be null or empty"); } try { LOGGER.info("Creating table: " + tableName + " with GSI: " + indexName); CreateTableRequest createTableRequest = CreateTableRequest.builder() .tableName(tableName) .attributeDefinitions( AttributeDefinition.builder() .attributeName("Artist") .attributeType(ScalarAttributeType.S) .build(), AttributeDefinition.builder() .attributeName("SongTitle") .attributeType(ScalarAttributeType.S) .build()) .keySchema( KeySchemaElement.builder() .attributeName("Artist") .keyType(KeyType.HASH) .build(), KeySchemaElement.builder() .attributeName("SongTitle") .keyType(KeyType.RANGE) .build()) .billingMode(BillingMode.PAY_PER_REQUEST) .globalSecondaryIndexes(GlobalSecondaryIndex.builder() .indexName(indexName) .keySchema(KeySchemaElement.builder() .attributeName("SongTitle") .keyType(KeyType.HASH) .build()) .projection( Projection.builder().projectionType(ProjectionType.ALL).build()) .build()) .streamSpecification(StreamSpecification.builder() .streamEnabled(true) .streamViewType(StreamViewType.NEW_AND_OLD_IMAGES) .build()) .build(); CreateTableResponse response = dynamoDbClient.createTable(createTableRequest); LOGGER.info("Table creation initiated. Status: " + response.tableDescription().tableStatus()); return response; } catch (DynamoDbException e) { LOGGER.severe("Failed to create table: " + tableName + " - " + e.getMessage()); throw e; } }

Attendi che una tabella diventi attiva utilizzando. AWS SDK for Java 2.x

public static void waitForTableActive(final DynamoDbClient dynamoDbClient, final String tableName) { if (dynamoDbClient == null) { throw new IllegalArgumentException("DynamoDB client cannot be null"); } if (tableName == null || tableName.trim().isEmpty()) { throw new IllegalArgumentException("Table name cannot be null or empty"); } try { LOGGER.info("Waiting for table to become active: " + tableName); try (DynamoDbWaiter waiter = DynamoDbWaiter.builder().client(dynamoDbClient).build()) { DescribeTableRequest request = DescribeTableRequest.builder().tableName(tableName).build(); waiter.waitUntilTableExists(request); LOGGER.info("Table is now active: " + tableName); } } catch (DynamoDbException e) { LOGGER.severe("Failed to wait for table to become active: " + tableName + " - " + e.getMessage()); throw e; } }

Aggiungi una replica per creare o estendere una tabella globale utilizzando AWS SDK for Java 2.x.

public static UpdateTableResponse addReplica( final DynamoDbClient dynamoDbClient, final String tableName, final Region replicaRegion, final String indexName, final Long readCapacity) { if (dynamoDbClient == null) { throw new IllegalArgumentException("DynamoDB client cannot be null"); } if (tableName == null || tableName.trim().isEmpty()) { throw new IllegalArgumentException("Table name cannot be null or empty"); } if (replicaRegion == null) { throw new IllegalArgumentException("Replica region cannot be null"); } if (indexName == null || indexName.trim().isEmpty()) { throw new IllegalArgumentException("Index name cannot be null or empty"); } if (readCapacity == null || readCapacity <= 0) { throw new IllegalArgumentException("Read capacity must be a positive number"); } try { LOGGER.info("Adding replica in region: " + replicaRegion.id() + " for table: " + tableName); // Create a ReplicationGroupUpdate for adding a replica ReplicationGroupUpdate replicationGroupUpdate = ReplicationGroupUpdate.builder() .create(builder -> builder.regionName(replicaRegion.id()) .globalSecondaryIndexes(ReplicaGlobalSecondaryIndex.builder() .indexName(indexName) .provisionedThroughputOverride(ProvisionedThroughputOverride.builder() .readCapacityUnits(readCapacity) .build()) .build()) .build()) .build(); UpdateTableRequest updateTableRequest = UpdateTableRequest.builder() .tableName(tableName) .replicaUpdates(replicationGroupUpdate) .build(); UpdateTableResponse response = dynamoDbClient.updateTable(updateTableRequest); LOGGER.info("Replica addition initiated in region: " + replicaRegion.id()); return response; } catch (DynamoDbException e) { LOGGER.severe("Failed to add replica in region: " + replicaRegion.id() + " - " + e.getMessage()); throw e; } }

Rimuovi una replica da una tabella globale utilizzando. AWS SDK for Java 2.x

public static UpdateTableResponse removeReplica( final DynamoDbClient dynamoDbClient, final String tableName, final Region replicaRegion) { if (dynamoDbClient == null) { throw new IllegalArgumentException("DynamoDB client cannot be null"); } if (tableName == null || tableName.trim().isEmpty()) { throw new IllegalArgumentException("Table name cannot be null or empty"); } if (replicaRegion == null) { throw new IllegalArgumentException("Replica region cannot be null"); } try { LOGGER.info("Removing replica in region: " + replicaRegion.id() + " for table: " + tableName); // Create a ReplicationGroupUpdate for removing a replica ReplicationGroupUpdate replicationGroupUpdate = ReplicationGroupUpdate.builder() .delete(builder -> builder.regionName(replicaRegion.id()).build()) .build(); UpdateTableRequest updateTableRequest = UpdateTableRequest.builder() .tableName(tableName) .replicaUpdates(replicationGroupUpdate) .build(); UpdateTableResponse response = dynamoDbClient.updateTable(updateTableRequest); LOGGER.info("Replica removal initiated in region: " + replicaRegion.id()); return response; } catch (DynamoDbException e) { LOGGER.severe("Failed to remove replica in region: " + replicaRegion.id() + " - " + e.getMessage()); throw e; } }

Aggiungi elementi di test per verificare la replica utilizzando. AWS SDK for Java 2.x

public static PutItemResponse putTestItem( final DynamoDbClient dynamoDbClient, final String tableName, final String artist, final String songTitle) { if (dynamoDbClient == null) { throw new IllegalArgumentException("DynamoDB client cannot be null"); } if (tableName == null || tableName.trim().isEmpty()) { throw new IllegalArgumentException("Table name cannot be null or empty"); } if (artist == null || artist.trim().isEmpty()) { throw new IllegalArgumentException("Artist cannot be null or empty"); } if (songTitle == null || songTitle.trim().isEmpty()) { throw new IllegalArgumentException("Song title cannot be null or empty"); } try { LOGGER.info("Adding test item to table: " + tableName); Map<String, software.amazon.awssdk.services.dynamodb.model.AttributeValue> item = new HashMap<>(); item.put( "Artist", software.amazon.awssdk.services.dynamodb.model.AttributeValue.builder() .s(artist) .build()); item.put( "SongTitle", software.amazon.awssdk.services.dynamodb.model.AttributeValue.builder() .s(songTitle) .build()); PutItemRequest putItemRequest = PutItemRequest.builder().tableName(tableName).item(item).build(); PutItemResponse response = dynamoDbClient.putItem(putItemRequest); LOGGER.info("Test item added successfully"); return response; } catch (DynamoDbException e) { LOGGER.severe("Failed to add test item to table: " + tableName + " - " + e.getMessage()); throw e; } }

Descrivi la configurazione globale della tabella e le repliche utilizzando. AWS SDK for Java 2.x

public static DescribeTableResponse describeTable(final DynamoDbClient dynamoDbClient, final String tableName) { if (dynamoDbClient == null) { throw new IllegalArgumentException("DynamoDB client cannot be null"); } if (tableName == null || tableName.trim().isEmpty()) { throw new IllegalArgumentException("Table name cannot be null or empty"); } try { LOGGER.info("Describing table: " + tableName); DescribeTableRequest request = DescribeTableRequest.builder().tableName(tableName).build(); DescribeTableResponse response = dynamoDbClient.describeTable(request); LOGGER.info("Table status: " + response.table().tableStatus()); if (response.table().replicas() != null && !response.table().replicas().isEmpty()) { LOGGER.info("Number of replicas: " + response.table().replicas().size()); response.table() .replicas() .forEach(replica -> LOGGER.info( "Replica region: " + replica.regionName() + ", Status: " + replica.replicaStatus())); } return response; } catch (ResourceNotFoundException e) { LOGGER.severe("Table not found: " + tableName + " - " + e.getMessage()); throw e; } catch (DynamoDbException e) { LOGGER.severe("Failed to describe table: " + tableName + " - " + e.getMessage()); throw e; } }

Esempio completo di operazioni su tabelle globali utilizzando AWS SDK for Java 2.x.

public static void exampleUsage(final Region sourceRegion, final Region replicaRegion) { String tableName = "Music"; String indexName = "SongTitleIndex"; Long readCapacity = 15L; // Create DynamoDB client for the source region try (DynamoDbClient dynamoDbClient = DynamoDbClient.builder().region(sourceRegion).build()) { try { // Step 1: Create the initial table with GSI and streams LOGGER.info("Step 1: Creating table in source region: " + sourceRegion.id()); createTableWithGSI(dynamoDbClient, tableName, indexName); // Step 2: Wait for table to become active LOGGER.info("Step 2: Waiting for table to become active"); waitForTableActive(dynamoDbClient, tableName); // Step 3: Add replica in destination region LOGGER.info("Step 3: Adding replica in region: " + replicaRegion.id()); addReplica(dynamoDbClient, tableName, replicaRegion, indexName, readCapacity); // Step 4: Wait a moment for replica creation to start Thread.sleep(5000); // Step 5: Describe table to view replica information LOGGER.info("Step 5: Describing table to view replicas"); describeTable(dynamoDbClient, tableName); // Step 6: Add a test item to verify replication LOGGER.info("Step 6: Adding test item to verify replication"); putTestItem(dynamoDbClient, tableName, "TestArtist", "TestSong"); LOGGER.info("Global table setup completed successfully!"); LOGGER.info("You can verify replication by checking the item in region: " + replicaRegion.id()); // Step 7: Remove replica and clean up table LOGGER.info("Step 7: Removing replica from region: " + replicaRegion.id()); removeReplica(dynamoDbClient, tableName, replicaRegion); DeleteTableResponse deleteTableResponse = dynamoDbClient.deleteTable( DeleteTableRequest.builder().tableName(tableName).build()); LOGGER.info("MREC global table demonstration completed successfully!"); } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw new RuntimeException("Thread was interrupted", e); } catch (DynamoDbException e) { LOGGER.severe("DynamoDB operation failed: " + e.getMessage()); throw e; } } }

Creazione di una tabella globale configurata per MRSC

Questa sezione mostra come creare una tabella globale a elevata consistenza multi-Regione (MRSC). Le tabelle globali MRSC replicano in modo sincrono le modifiche agli elementi tra le Regioni, garantendo che le operazioni a elevata consistenza di lettura su qualsiasi replica restituiscano sempre la versione più recente di un elemento. Quando si converte una tabella a Regione singola in una tabella globale MRSC, è necessario assicurarsi che la tabella sia vuota. La conversione di una tabella a Regione singola in una tabella globale MRSC con elementi esistenti non è supportata. Assicurati che non venga scritto alcun dato nella tabella durante il processo di conversione.

È possibile configurare una tabella globale MRSC con tre repliche o con due repliche e un testimone. Quando si crea una tabella globale MRSC, si scelgono le Regioni in cui vengono distribuite le repliche e un testimone opzionale. L’esempio seguente crea una tabella globale MRSC con repliche nelle Regioni Stati Uniti orientali (Virginia settentrionale) e Stati Uniti orientali (Ohio), con un testimone nella Regione Stati Uniti occidentali (Oregon).

Nota

Prima di creare una tabella globale, verifica che i limiti di throughput della quota di servizio siano coerenti in tutte le Regioni di destinazione, poiché ciò è necessario per creare una tabella globale. Per ulteriori informazioni sui limiti di throughput delle tabelle globali, consulta Quote delle tabelle globali.

Completa questa procedura per creare una tabella globale MRSC utilizzando la Console di gestione AWS.

  1. Accedi Console di gestione AWS e apri la console DynamoDB all'indirizzo. https://console.aws.amazon.com/dynamodb/

  2. Dal selettore delle Regioni nella barra di navigazione, seleziona una Regione in cui sono supportate le tabelle globali con MRSC, ad esempio us-east-2.

  3. Nel pannello di navigazione, seleziona Tabelle.

  4. Scegliere Create table (Crea tabella).

  5. Nella pagina Crea tabella:

    1. Nel campo Table name (Nome tabella) immetti Music.

    2. Per Chiave di partizione immetti Artist e mantieni il tipo di Stringa predefinito.

    3. Per Chiave di ordinamento immetti SongTitle e mantieni il tipo di Stringa predefinito.

    4. Mantieni le restanti impostazioni predefinite e seleziona Crea tabella.

      Questa nuova tabella funge da prima tabella di replica in una nuova tabella globale. È il prototipo per altre tabelle di replica che verranno aggiunte in seguito.

  6. Attendi che la tabella diventi attiva, quindi selezionala dall’elenco delle tabelle.

  7. Seleziona la scheda Tabelle globali, quindi seleziona Crea replica.

  8. Nella pagina Crea replica:

    1. In Coerenza multi-Regione, seleziona Coerenza forte.

    2. Per Regione di replica 1, seleziona US East (N. Virginia) us-east-1.

    3. Per Regione di replica 2, seleziona US West (Oregon) us-west-2.

    4. Seleziona Configura come testimone per la Regione Stati Uniti occidentali (Oregon).

    5. Seleziona Crea repliche.

  9. Attendi il completamento della replica e del processo di creazione del testimone. Lo stato della replica verrà visualizzato come Attivo quando la tabella sarà pronta per l’uso.

Prima di iniziare, assicurati che il principale IAM disponga delle autorizzazioni necessarie per creare una tabella globale MRSC con una Regione testimone.

La seguente policy IAM di esempio consente di creare una tabella DynamoDB (MusicTable) negli Stati Uniti orientali (Ohio) con una replica nella Regione Stati Uniti orientali (Virginia settentrionale) e una Regione testimone negli Stati Uniti occidentali (Oregon):

JSON
{ "Version":"2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "dynamodb:CreateTable", "dynamodb:CreateTableReplica", "dynamodb:CreateGlobalTableWitness", "dynamodb:DescribeTable", "dynamodb:UpdateTable", "dynamodb:DeleteTable", "dynamodb:DeleteTableReplica", "dynamodb:DeleteGlobalTableWitness", "dynamodb:Scan", "dynamodb:Query", "dynamodb:UpdateItem", "dynamodb:PutItem", "dynamodb:GetItem", "dynamodb:DeleteItem", "dynamodb:BatchWriteItem" ], "Resource": [ "arn:aws:dynamodb:us-east-1:123456789012:table/MusicTable", "arn:aws:dynamodb:us-east-2:123456789012:table/MusicTable", "arn:aws:dynamodb:us-west-2:123456789012:table/MusicTable" ] }, { "Effect": "Allow", "Action": "iam:CreateServiceLinkedRole", "Resource": "arn:aws:iam::*:role/aws-service-role/replication.dynamodb.amazonaws.com/AWSServiceRoleForDynamoDBReplication", "Condition": { "StringLike": { "iam:AWSServiceName": "replication.dynamodb.amazonaws.com" } } } ] }

Gli esempi di codice seguenti mostrano come creare e gestire tabelle globali DynamoDB con elevata consistenza multi-Regione (MRSC).

  • Creazione di una tabella con elevata consistenza multi-Regione.

  • Verifica della configurazione MRSC e dello stato della replica.

  • Verifica dell’elevata consistenza tra Regioni con letture immediate.

  • Esecuzione di scritture condizionali con garanzie MRSC.

  • Esecuzione della pulizia delle risorse su una tabella globale MRSC.

Bash
AWS CLI con lo script Bash

Creazione di una tabella con elevata consistenza multi-Regione.

# Step 1: Create a new table in us-east-2 (primary region for MRSC) # Note: Table must be empty when enabling MRSC aws dynamodb create-table \ --table-name MusicTable \ --attribute-definitions \ AttributeName=Artist,AttributeType=S \ AttributeName=SongTitle,AttributeType=S \ --key-schema \ AttributeName=Artist,KeyType=HASH \ AttributeName=SongTitle,KeyType=RANGE \ --billing-mode PAY_PER_REQUEST \ --region us-east-2 # Wait for table to become active aws dynamodb wait table-exists --table-name MusicTable --region us-east-2 # Step 2: Add replica and witness with Multi-Region Strong Consistency # MRSC requires exactly three replicas in supported regions aws dynamodb update-table \ --table-name MusicTable \ --replica-updates '[{"Create": {"RegionName": "us-east-1"}}]' \ --global-table-witness-updates '[{"Create": {"RegionName": "us-west-2"}}]' \ --multi-region-consistency STRONG \ --region us-east-2

Verifica della configurazione MRSC e dello stato della replica.

# Verify the global table configuration and MRSC setting aws dynamodb describe-table \ --table-name MusicTable \ --region us-east-2 \ --query 'Table.{TableName:TableName,TableStatus:TableStatus,MultiRegionConsistency:MultiRegionConsistency,Replicas:Replicas[*],GlobalTableWitnesses:GlobalTableWitnesses[*].{Region:RegionName,Status:ReplicaStatus}}'

Verifica della coerenza forte multi-Regione con letture immediate.

# Write an item to the primary region aws dynamodb put-item \ --table-name MusicTable \ --item '{"Artist": {"S":"The Beatles"},"SongTitle": {"S":"Hey Jude"},"Album": {"S":"The Beatles 1967-1970"},"Year": {"N":"1968"}}' \ --region us-east-2 # Read the item from replica region to verify strong consistency (cannot read or write to witness) # No wait time needed - MRSC provides immediate consistency echo "Reading from us-east-1 (immediate consistency):" aws dynamodb get-item \ --table-name MusicTable \ --key '{"Artist": {"S":"The Beatles"},"SongTitle": {"S":"Hey Jude"}}' \ --consistent-read \ --region us-east-1

Esecuzione di scritture condizionali con garanzie MRSC.

# Perform a conditional update from a different region # This demonstrates that conditions work consistently across all regions aws dynamodb update-item \ --table-name MusicTable \ --key '{"Artist": {"S":"The Beatles"},"SongTitle": {"S":"Hey Jude"}}' \ --update-expression "SET #rating = :rating" \ --condition-expression "attribute_exists(Artist)" \ --expression-attribute-names '{"#rating": "Rating"}' \ --expression-attribute-values '{":rating": {"N":"5"}}' \ --region us-east-1

Esecuzione della pulizia delle risorse su una tabella globale MRSC.

# Remove replica tables (must be done before deleting the primary table) aws dynamodb update-table \ --table-name MusicTable \ --replica-updates '[{"Delete": {"RegionName": "us-east-1"}}]' \ --global-table-witness-updates '[{"Delete": {"RegionName": "us-west-2"}}]' \ --region us-east-2 # Wait for replicas to be deleted echo "Waiting for replicas to be deleted..." sleep 30 # Delete the primary table aws dynamodb delete-table \ --table-name MusicTable \ --region us-east-2
Java
SDK per Java 2.x

Crea una tabella regionale pronta per la conversione MRSC utilizzando. AWS SDK for Java 2.x

public static CreateTableResponse createRegionalTable(final DynamoDbClient dynamoDbClient, final String tableName) { if (dynamoDbClient == null) { throw new IllegalArgumentException("DynamoDB client cannot be null"); } if (tableName == null || tableName.trim().isEmpty()) { throw new IllegalArgumentException("Table name cannot be null or empty"); } try { LOGGER.info("Creating regional table: " + tableName + " (must be empty for MRSC)"); CreateTableRequest createTableRequest = CreateTableRequest.builder() .tableName(tableName) .attributeDefinitions( AttributeDefinition.builder() .attributeName("Artist") .attributeType(ScalarAttributeType.S) .build(), AttributeDefinition.builder() .attributeName("SongTitle") .attributeType(ScalarAttributeType.S) .build()) .keySchema( KeySchemaElement.builder() .attributeName("Artist") .keyType(KeyType.HASH) .build(), KeySchemaElement.builder() .attributeName("SongTitle") .keyType(KeyType.RANGE) .build()) .billingMode(BillingMode.PAY_PER_REQUEST) .build(); CreateTableResponse response = dynamoDbClient.createTable(createTableRequest); LOGGER.info("Regional table creation initiated. Status: " + response.tableDescription().tableStatus()); return response; } catch (DynamoDbException e) { LOGGER.severe("Failed to create regional table: " + tableName + " - " + e.getMessage()); throw DynamoDbException.builder() .message("Failed to create regional table: " + tableName) .cause(e) .build(); } }

Converti una tabella regionale in MRSC con repliche e verifica utilizzando. AWS SDK for Java 2.x

public static UpdateTableResponse convertToMRSCWithWitness( final DynamoDbClient dynamoDbClient, final String tableName, final Region replicaRegion, final Region witnessRegion) { if (dynamoDbClient == null) { throw new IllegalArgumentException("DynamoDB client cannot be null"); } if (tableName == null || tableName.trim().isEmpty()) { throw new IllegalArgumentException("Table name cannot be null or empty"); } if (replicaRegion == null) { throw new IllegalArgumentException("Replica region cannot be null"); } if (witnessRegion == null) { throw new IllegalArgumentException("Witness region cannot be null"); } try { LOGGER.info("Converting table to MRSC with replica in " + replicaRegion.id() + " and witness in " + witnessRegion.id()); // Create replica update using ReplicationGroupUpdate ReplicationGroupUpdate replicaUpdate = ReplicationGroupUpdate.builder() .create(CreateReplicationGroupMemberAction.builder() .regionName(replicaRegion.id()) .build()) .build(); // Create witness update GlobalTableWitnessGroupUpdate witnessUpdate = GlobalTableWitnessGroupUpdate.builder() .create(CreateGlobalTableWitnessGroupMemberAction.builder() .regionName(witnessRegion.id()) .build()) .build(); UpdateTableRequest updateTableRequest = UpdateTableRequest.builder() .tableName(tableName) .replicaUpdates(List.of(replicaUpdate)) .globalTableWitnessUpdates(List.of(witnessUpdate)) .multiRegionConsistency(MultiRegionConsistency.STRONG) .build(); UpdateTableResponse response = dynamoDbClient.updateTable(updateTableRequest); LOGGER.info("MRSC conversion initiated. Status: " + response.tableDescription().tableStatus()); LOGGER.info("UpdateTableResponse full object: " + response); return response; } catch (DynamoDbException e) { LOGGER.severe("Failed to convert table to MRSC: " + tableName + " - " + e.getMessage()); throw DynamoDbException.builder() .message("Failed to convert table to MRSC: " + tableName) .cause(e) .build(); } }

Descrivi una configurazione di tabella globale MRSC utilizzando. AWS SDK for Java 2.x

public static DescribeTableResponse describeMRSCTable(final DynamoDbClient dynamoDbClient, final String tableName) { if (dynamoDbClient == null) { throw new IllegalArgumentException("DynamoDB client cannot be null"); } if (tableName == null || tableName.trim().isEmpty()) { throw new IllegalArgumentException("Table name cannot be null or empty"); } try { LOGGER.info("Describing MRSC global table: " + tableName); DescribeTableRequest request = DescribeTableRequest.builder().tableName(tableName).build(); DescribeTableResponse response = dynamoDbClient.describeTable(request); LOGGER.info("Table status: " + response.table().tableStatus()); LOGGER.info("Multi-region consistency: " + response.table().multiRegionConsistency()); if (response.table().replicas() != null && !response.table().replicas().isEmpty()) { LOGGER.info("Number of replicas: " + response.table().replicas().size()); response.table() .replicas() .forEach(replica -> LOGGER.info( "Replica region: " + replica.regionName() + ", Status: " + replica.replicaStatus())); } if (response.table().globalTableWitnesses() != null && !response.table().globalTableWitnesses().isEmpty()) { LOGGER.info("Number of witnesses: " + response.table().globalTableWitnesses().size()); response.table() .globalTableWitnesses() .forEach(witness -> LOGGER.info( "Witness region: " + witness.regionName() + ", Status: " + witness.witnessStatus())); } return response; } catch (ResourceNotFoundException e) { LOGGER.severe("Table not found: " + tableName + " - " + e.getMessage()); throw DynamoDbException.builder() .message("Table not found: " + tableName) .cause(e) .build(); } catch (DynamoDbException e) { LOGGER.severe("Failed to describe table: " + tableName + " - " + e.getMessage()); throw DynamoDbException.builder() .message("Failed to describe table: " + tableName) .cause(e) .build(); } }

Per aggiungere elementi di test per verificare l’elevata consistenza MRSC con AWS SDK for Java 2.x.

public static PutItemResponse putTestItem( final DynamoDbClient dynamoDbClient, final String tableName, final String artist, final String songTitle, final String album, final String year) { if (dynamoDbClient == null) { throw new IllegalArgumentException("DynamoDB client cannot be null"); } if (tableName == null || tableName.trim().isEmpty()) { throw new IllegalArgumentException("Table name cannot be null or empty"); } if (artist == null || artist.trim().isEmpty()) { throw new IllegalArgumentException("Artist cannot be null or empty"); } if (songTitle == null || songTitle.trim().isEmpty()) { throw new IllegalArgumentException("Song title cannot be null or empty"); } try { LOGGER.info("Adding test item to MRSC global table: " + tableName); Map<String, AttributeValue> item = new HashMap<>(); item.put("Artist", AttributeValue.builder().s(artist).build()); item.put("SongTitle", AttributeValue.builder().s(songTitle).build()); if (album != null && !album.trim().isEmpty()) { item.put("Album", AttributeValue.builder().s(album).build()); } if (year != null && !year.trim().isEmpty()) { item.put("Year", AttributeValue.builder().n(year).build()); } PutItemRequest putItemRequest = PutItemRequest.builder().tableName(tableName).item(item).build(); PutItemResponse response = dynamoDbClient.putItem(putItemRequest); LOGGER.info("Test item added successfully with strong consistency"); return response; } catch (DynamoDbException e) { LOGGER.severe("Failed to add test item to table: " + tableName + " - " + e.getMessage()); throw DynamoDbException.builder() .message("Failed to add test item to table: " + tableName) .cause(e) .build(); } }

Leggi gli elementi con letture coerenti dalle repliche MRSC utilizzando. AWS SDK for Java 2.x

public static GetItemResponse getItemWithConsistentRead( final DynamoDbClient dynamoDbClient, final String tableName, final String artist, final String songTitle) { if (dynamoDbClient == null) { throw new IllegalArgumentException("DynamoDB client cannot be null"); } if (tableName == null || tableName.trim().isEmpty()) { throw new IllegalArgumentException("Table name cannot be null or empty"); } if (artist == null || artist.trim().isEmpty()) { throw new IllegalArgumentException("Artist cannot be null or empty"); } if (songTitle == null || songTitle.trim().isEmpty()) { throw new IllegalArgumentException("Song title cannot be null or empty"); } try { LOGGER.info("Reading item from MRSC global table with consistent read: " + tableName); Map<String, AttributeValue> key = new HashMap<>(); key.put("Artist", AttributeValue.builder().s(artist).build()); key.put("SongTitle", AttributeValue.builder().s(songTitle).build()); GetItemRequest getItemRequest = GetItemRequest.builder() .tableName(tableName) .key(key) .consistentRead(true) .build(); GetItemResponse response = dynamoDbClient.getItem(getItemRequest); if (response.hasItem()) { LOGGER.info("Item found with strong consistency - no wait time needed"); } else { LOGGER.info("Item not found"); } return response; } catch (DynamoDbException e) { LOGGER.severe("Failed to read item from table: " + tableName + " - " + e.getMessage()); throw DynamoDbException.builder() .message("Failed to read item from table: " + tableName) .cause(e) .build(); } }

Esegui aggiornamenti condizionali con garanzie MRSC utilizzando. AWS SDK for Java 2.x

public static UpdateItemResponse performConditionalUpdate( final DynamoDbClient dynamoDbClient, final String tableName, final String artist, final String songTitle, final String rating) { if (dynamoDbClient == null) { throw new IllegalArgumentException("DynamoDB client cannot be null"); } if (tableName == null || tableName.trim().isEmpty()) { throw new IllegalArgumentException("Table name cannot be null or empty"); } if (artist == null || artist.trim().isEmpty()) { throw new IllegalArgumentException("Artist cannot be null or empty"); } if (songTitle == null || songTitle.trim().isEmpty()) { throw new IllegalArgumentException("Song title cannot be null or empty"); } if (rating == null || rating.trim().isEmpty()) { throw new IllegalArgumentException("Rating cannot be null or empty"); } try { LOGGER.info("Performing conditional update on MRSC global table: " + tableName); Map<String, AttributeValue> key = new HashMap<>(); key.put("Artist", AttributeValue.builder().s(artist).build()); key.put("SongTitle", AttributeValue.builder().s(songTitle).build()); Map<String, String> expressionAttributeNames = new HashMap<>(); expressionAttributeNames.put("#rating", "Rating"); Map<String, AttributeValue> expressionAttributeValues = new HashMap<>(); expressionAttributeValues.put( ":rating", AttributeValue.builder().n(rating).build()); UpdateItemRequest updateItemRequest = UpdateItemRequest.builder() .tableName(tableName) .key(key) .updateExpression("SET #rating = :rating") .conditionExpression("attribute_exists(Artist)") .expressionAttributeNames(expressionAttributeNames) .expressionAttributeValues(expressionAttributeValues) .build(); UpdateItemResponse response = dynamoDbClient.updateItem(updateItemRequest); LOGGER.info("Conditional update successful - demonstrates strong consistency"); return response; } catch (ConditionalCheckFailedException e) { LOGGER.warning("Conditional check failed: " + e.getMessage()); throw e; } catch (DynamoDbException e) { LOGGER.severe("Failed to perform conditional update: " + tableName + " - " + e.getMessage()); throw DynamoDbException.builder() .message("Failed to perform conditional update: " + tableName) .cause(e) .build(); } }

Attendi che le repliche e i testimoni MRSC diventino attivi utilizzando. AWS SDK for Java 2.x

public static void waitForMRSCReplicasActive( final DynamoDbClient dynamoDbClient, final String tableName, final int maxWaitTimeSeconds) throws InterruptedException { if (dynamoDbClient == null) { throw new IllegalArgumentException("DynamoDB client cannot be null"); } if (tableName == null || tableName.trim().isEmpty()) { throw new IllegalArgumentException("Table name cannot be null or empty"); } if (maxWaitTimeSeconds <= 0) { throw new IllegalArgumentException("Max wait time must be positive"); } try { LOGGER.info("Waiting for MRSC replicas and witnesses to become active: " + tableName); final long startTime = System.currentTimeMillis(); final long maxWaitTimeMillis = maxWaitTimeSeconds * 1000L; int backoffSeconds = 5; // Start with 5 second intervals final int maxBackoffSeconds = 30; // Cap at 30 seconds while (System.currentTimeMillis() - startTime < maxWaitTimeMillis) { DescribeTableResponse response = describeMRSCTable(dynamoDbClient, tableName); boolean allActive = true; StringBuilder statusReport = new StringBuilder(); if (response.table().multiRegionConsistency() == null || !MultiRegionConsistency.STRONG .toString() .equals(response.table().multiRegionConsistency().toString())) { allActive = false; statusReport .append("MultiRegionConsistency: ") .append(response.table().multiRegionConsistency()) .append(" "); } if (response.table().replicas() == null || response.table().replicas().isEmpty()) { allActive = false; statusReport.append("No replicas found. "); } if (response.table().globalTableWitnesses() == null || response.table().globalTableWitnesses().isEmpty()) { allActive = false; statusReport.append("No witnesses found. "); } // Check table status if (!"ACTIVE".equals(response.table().tableStatus().toString())) { allActive = false; statusReport .append("Table: ") .append(response.table().tableStatus()) .append(" "); } // Check replica status if (response.table().replicas() != null) { for (var replica : response.table().replicas()) { if (!"ACTIVE".equals(replica.replicaStatus().toString())) { allActive = false; statusReport .append("Replica(") .append(replica.regionName()) .append("): ") .append(replica.replicaStatus()) .append(" "); } } } // Check witness status if (response.table().globalTableWitnesses() != null) { for (var witness : response.table().globalTableWitnesses()) { if (!"ACTIVE".equals(witness.witnessStatus().toString())) { allActive = false; statusReport .append("Witness(") .append(witness.regionName()) .append("): ") .append(witness.witnessStatus()) .append(" "); } } } if (allActive) { LOGGER.info("All MRSC replicas and witnesses are now active: " + tableName); return; } LOGGER.info("Waiting for MRSC components to become active. Status: " + statusReport.toString()); LOGGER.info("Next check in " + backoffSeconds + " seconds..."); tempWait(backoffSeconds); // Exponential backoff with cap backoffSeconds = Math.min(backoffSeconds * 2, maxBackoffSeconds); } throw DynamoDbException.builder() .message("Timeout waiting for MRSC replicas to become active after " + maxWaitTimeSeconds + " seconds") .build(); } catch (DynamoDbException | InterruptedException e) { LOGGER.severe("Failed to wait for MRSC replicas to become active: " + tableName + " - " + e.getMessage()); throw e; } }

Pulisci le repliche e i testimoni MRSC utilizzando. AWS SDK for Java 2.x

public static UpdateTableResponse cleanupMRSCReplicas( final DynamoDbClient dynamoDbClient, final String tableName, final Region replicaRegion, final Region witnessRegion) { if (dynamoDbClient == null) { throw new IllegalArgumentException("DynamoDB client cannot be null"); } if (tableName == null || tableName.trim().isEmpty()) { throw new IllegalArgumentException("Table name cannot be null or empty"); } if (replicaRegion == null) { throw new IllegalArgumentException("Replica region cannot be null"); } if (witnessRegion == null) { throw new IllegalArgumentException("Witness region cannot be null"); } try { LOGGER.info("Cleaning up MRSC replicas and witnesses for table: " + tableName); // Remove replica using ReplicationGroupUpdate ReplicationGroupUpdate replicaUpdate = ReplicationGroupUpdate.builder() .delete(DeleteReplicationGroupMemberAction.builder() .regionName(replicaRegion.id()) .build()) .build(); // Remove witness GlobalTableWitnessGroupUpdate witnessUpdate = GlobalTableWitnessGroupUpdate.builder() .delete(DeleteGlobalTableWitnessGroupMemberAction.builder() .regionName(witnessRegion.id()) .build()) .build(); UpdateTableRequest updateTableRequest = UpdateTableRequest.builder() .tableName(tableName) .replicaUpdates(List.of(replicaUpdate)) .globalTableWitnessUpdates(List.of(witnessUpdate)) .build(); UpdateTableResponse response = dynamoDbClient.updateTable(updateTableRequest); LOGGER.info("MRSC cleanup initiated - removing replica and witness. Response: " + response); return response; } catch (DynamoDbException e) { LOGGER.severe("Failed to cleanup MRSC replicas: " + tableName + " - " + e.getMessage()); throw DynamoDbException.builder() .message("Failed to cleanup MRSC replicas: " + tableName) .cause(e) .build(); } }

Dimostrazione completa del flusso di lavoro MRSC utilizzando. AWS SDK for Java 2.x

public static void demonstrateCompleteMRSCWorkflow( final DynamoDbClient primaryClient, final DynamoDbClient replicaClient, final String tableName, final Region replicaRegion, final Region witnessRegion) throws InterruptedException { if (primaryClient == null) { throw new IllegalArgumentException("Primary DynamoDB client cannot be null"); } if (replicaClient == null) { throw new IllegalArgumentException("Replica DynamoDB client cannot be null"); } if (tableName == null || tableName.trim().isEmpty()) { throw new IllegalArgumentException("Table name cannot be null or empty"); } if (replicaRegion == null) { throw new IllegalArgumentException("Replica region cannot be null"); } if (witnessRegion == null) { throw new IllegalArgumentException("Witness region cannot be null"); } try { LOGGER.info("=== Starting Complete MRSC Workflow Demonstration ==="); // Step 1: Create an empty single-Region table LOGGER.info("Step 1: Creating empty single-Region table"); createRegionalTable(primaryClient, tableName); // Use the existing GlobalTableOperations method for basic table waiting LOGGER.info("Intermediate step: Waiting for table [" + tableName + "] to become active before continuing"); GlobalTableOperations.waitForTableActive(primaryClient, tableName); // Step 2: Convert to MRSC with replica and witness LOGGER.info("Step 2: Converting to MRSC with replica and witness"); convertToMRSCWithWitness(primaryClient, tableName, replicaRegion, witnessRegion); // Wait for MRSC conversion to complete using MRSC-specific waiter LOGGER.info("Waiting for MRSC conversion to complete..."); waitForMRSCReplicasActive(primaryClient, tableName); LOGGER.info("Intermediate step: Waiting for table [" + tableName + "] to become active before continuing"); GlobalTableOperations.waitForTableActive(primaryClient, tableName); // Step 3: Verify MRSC configuration LOGGER.info("Step 3: Verifying MRSC configuration"); describeMRSCTable(primaryClient, tableName); // Step 4: Test strong consistency with data operations LOGGER.info("Step 4: Testing strong consistency with data operations"); // Add test item to primary region putTestItem(primaryClient, tableName, "The Beatles", "Hey Jude", "The Beatles 1967-1970", "1968"); // Immediately read from replica region (no wait needed with MRSC) LOGGER.info("Reading from replica region immediately (strong consistency):"); GetItemResponse getResponse = getItemWithConsistentRead(replicaClient, tableName, "The Beatles", "Hey Jude"); if (getResponse.hasItem()) { LOGGER.info("✓ Strong consistency verified - item immediately available in replica region"); } else { LOGGER.warning("✗ Item not found in replica region"); } // Test conditional update from replica region LOGGER.info("Testing conditional update from replica region:"); performConditionalUpdate(replicaClient, tableName, "The Beatles", "Hey Jude", "5"); LOGGER.info("✓ Conditional update successful - demonstrates strong consistency"); // Step 5: Cleanup LOGGER.info("Step 5: Cleaning up resources"); cleanupMRSCReplicas(primaryClient, tableName, replicaRegion, witnessRegion); // Wait for cleanup to complete using basic table waiter LOGGER.info("Waiting for replica cleanup to complete..."); GlobalTableOperations.waitForTableActive(primaryClient, tableName); // "Halt" until replica/witness cleanup is complete DescribeTableResponse cleanupVerification = describeMRSCTable(primaryClient, tableName); int backoffSeconds = 5; // Start with 5 second intervals while (cleanupVerification.table().multiRegionConsistency() != null) { LOGGER.info("Waiting additional time (" + backoffSeconds + " seconds) for MRSC cleanup to complete..."); tempWait(backoffSeconds); // Exponential backoff with cap backoffSeconds = Math.min(backoffSeconds * 2, 30); cleanupVerification = describeMRSCTable(primaryClient, tableName); } // Delete the primary table deleteTable(primaryClient, tableName); LOGGER.info("=== MRSC Workflow Demonstration Complete ==="); LOGGER.info(""); LOGGER.info("Key benefits of Multi-Region Strong Consistency (MRSC):"); LOGGER.info("- Immediate consistency across all regions (no eventual consistency delays)"); LOGGER.info("- Simplified application logic (no need to handle eventual consistency)"); LOGGER.info("- Support for conditional writes and transactions across regions"); LOGGER.info("- Consistent read operations from any region without waiting"); } catch (DynamoDbException | InterruptedException e) { LOGGER.severe("MRSC workflow failed: " + e.getMessage()); throw e; } }