Tutorials: Erstellen von globalen Tabellen - Amazon-DynamoDB

Tutorials: Erstellen von globalen Tabellen

Dieser Abschnitt enthält Schritt-für-Schritt-Anleitungen zum Erstellen der globalen DynamoDB-Tabellen, die für Ihren bevorzugten Konsistenzmodus konfiguriert sind. Wählen Sie je nach Anforderungen der Anwendung entweder den Modus „Multi-Region Eventual Consistency (MREC)“ oder „Multi-Region Strong Consistency (MRSC)“ aus.

Globale MREC-Tabellen bieten eine geringere Schreiblatenz und sorgen letztendlich für Konsistenz über alle AWS-Regionen hinweg. Globale MRSC-Tabellen bieten strikt konsistente Lesevorgänge in allen Regionen und ermöglichen etwas höhere Schreiblatenzen als MREC-Tabellen. Wählen Sie den Konsistenzmodus, der den Anforderungen Ihrer Anwendung an Datenkonsistenz, Latenz und Verfügbarkeit am ehesten entspricht.

Erstellen einer globalen Tabelle, die für den MREC-Modus konfiguriert ist

In diesem Abschnitt erfahren Sie, wie Sie eine globale Tabelle im MREC-Modus (Multi-Region Eventual Consistency) erstellen. MREC ist der Standard-Konsistenzmodus für globale Tabellen und ermöglicht Schreibvorgänge mit geringer Latenz und asynchroner Replikation über alle AWS-Regionen hinweg. Änderungen, die in einer Region an einem Element vorgenommen werden, werden in der Regel innerhalb einer Sekunde auf alle anderen Regionen repliziert. Dadurch eignet sich der MREC-Modus ideal für Anwendungen, die einer geringen Schreiblatenz Priorität einräumen und tolerieren können, dass aus verschiedenen Regionen kurzzeitig Datenversionen mit geringen Unterschieden zurückgegeben werden.

Sie können globale MREC-Tabellen mit Replikaten in jeder AWS-Region erstellen, in der DynamoDB verfügbar ist. In den folgenden Beispielen wird gezeigt, wie eine globale DynamoDB-Tabelle mit Replikaten in mehreren Regionen erstellt wird.

Gehen Sie wie folgt vor, um eine globale Tabelle mit der AWS-Managementkonsole zu erstellen. Im folgenden Beispiel wird eine globale Tabelle mit Replikattabellen in den USA und Europa erstellt.

  1. Melden Sie sich bei AWS-Managementkonsole an und öffnen Sie die DynamoDB-Konsole unter https://console.aws.amazon.com/dynamodb/.

  2. Wählen Sie für dieses Beispiel in der Regionsauswahl in der Navigationsleiste die Region USA Ost (Ohio) aus.

  3. Klicken Sie im Navigationsbereich auf der linken Seite der Konsole auf Tabellen.

  4. Wählen Sie Tabelle erstellen aus.

  5. Gehen Sie auf der Seite Tabelle erstellen wie folgt vor:

    1. Geben Sie unter Tabellenname Music ein.

    2. Geben Sie unter Partitionsschlüssel den Wert Artist ein.

    3. Geben Sie unter (Sortierschlüssel) den Wert SongTitle ein.

    4. Behalten Sie die übrigen Standardeinstellungen bei und wählen Sie Tabelle erstellen aus.

      Diese neue Tabelle dient als erste Replikattabelle in einer neuen globalen Tabelle. Sie stellt den Prototyp für andere Replikattabellen dar, die Sie später hinzufügen.

  6. Gehen Sie folgendermaßen vor, wenn die Tabelle aktiv wird:

    1. Wählen Sie in der Tabellenliste die Tabelle Musik aus.

    2. Wählen Sie die Registerkarte Globale Tabellen aus.

    3. Wählen Sie die Option Replikat erstellen aus.

  7. Wählen Sie in der Dropdown-Liste Verfügbare Replikationsregionen den Eintrag USA West (Oregon) us-west-2 aus.

    Die Konsole stellt sicher, dass die ausgewählte Region keine Tabelle mit demselben Namen enthält. Wenn eine Tabelle mit demselben Namen vorhanden ist, müssen Sie die vorhandene Tabelle löschen, bevor Sie eine neue Replikattabelle in der betreffenden Region erstellen können.

  8. Wählen Sie die Option Replikat erstellen aus. Dies startet den Prozess der Erstellung von Tabellen in der Region „USA West (Oregon) us-west-2“.

    Die Registerkarte Globale Tabelle für die Tabelle Music (und für alle anderen Replikattabellen) zeigt, dass die Tabelle in mehreren Regionen repliziert wurde.

  9. Fügen Sie eine weitere Region hinzu, indem Sie die vorherigen Schritte wiederholen, aber als Region Europa (Frankfurt) eu-central-1 auswählen.

  10. So testen Sie die Replikation:

    1. Stellen Sie sicher, dass Sie die AWS-Managementkonsole in der Region „USA Ost (Ohio)“ verwenden.

    2. Wählen Sie Tabellenelemente erkunden aus.

    3. Wählen Sie Element erstellen aus.

    4. Geben Sie unter Artist item_1 und unter SongTitle Song Value 1 ein.

    5. Wählen Sie Element erstellen aus.

  11. Überprüfen Sie die Replikation, indem Sie zu den anderen Regionen wechseln:

    1. Wählen Sie in der Regionsauswahl in der rechten oberen Ecke Europa (Frankfurt) aus.

    2. Vergewissern Sie sich, dass die Tabelle Music das von Ihnen erstellte Objekt enthält.

    3. Wiederholen Sie die Überprüfung für USA West (Oregon).

CLI

Das folgende Codebeispiel zeigt, wie globale DynamoDB-Tabellen mit Multi-Region Eventual Consistency (MREC) verwaltet werden.

  • Erstellen Sie eine Tabelle mit multiregionaler Replikation (MREC).

  • Fügen Sie Elemente in eine Replikattabelle ein und rufen Sie Elemente aus der Tabelle ab.

  • Entfernen Sie die Replikate nacheinander.

  • Führen Sie eine Bereinigung durch Löschen der Tabelle aus.

AWS CLI mit Bash-Skript

Erstellen Sie eine Tabelle mit multiregionaler Replikation.

# 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

Beschreiben Sie die multiregionale Tabelle.

# 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}}'

Fügen Sie Elemente in eine Replikattabelle ein.

# 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

Rufen Sie Elemente aus Replikattabellen ab.

# 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

Entfernen Sie Replikate.

# 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

Führen Sie eine Bereinigung durch Löschen der Tabelle aus.

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

Im folgenden Codebeispiel wird gezeigt, wie globale DynamoDB-Tabellen mit Replikaten in mehreren Regionen erstellt und verwaltet werden.

  • Erstellen Sie eine Tabelle mit einem globalen sekundären Index und DynamoDB Streams.

  • Fügen Sie Replikate in verschiedenen Regionen hinzu, um eine globale Tabelle zu erstellen.

  • Entfernen Sie Replikate aus einer globalen Tabelle.

  • Fügen Sie Testelemente hinzu, um die regionsübergreifende Replikation zu überprüfen.

  • Beschreiben Sie die globale Tabellenkonfiguration und den Replikatstatus.

SDK für Java 2.x

Erstellen Sie mithilfe von AWS SDK for Java 2.x eine Tabelle mit einem globalen sekundären Index und DynamoDB Streams.

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; } }

Warten Sie, bis eine Tabelle mit AWS SDK for Java 2.x aktiviert wird.

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; } }

Fügen Sie mit AWS SDK for Java 2.x ein Replikat hinzu, um eine globale Tabelle zu erstellen oder zu erweitern.

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; } }

Entfernen Sie mithilfe von AWS SDK for Java 2.x ein Replikat aus einer globalen Tabelle.

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; } }

Fügen Sie Testelemente hinzu, um die Replikation mithilfe von AWS SDK for Java 2.x zu überprüfen.

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; } }

Beschreiben Sie die globale Tabellenkonfiguration und die Replikate mit 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; } }

Schließen Sie das Beispiel für globale Tabellenoperationen unter Verwendung von AWS SDK for Java 2.x ab.

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; } } }

Erstellen einer globalen Tabelle, die für den MRSC-Modus konfiguriert ist

In diesem Abschnitt erfahren Sie, wie Sie eine globale Tabelle im MRSC-Modus (Multi-Region Strong Consistency) erstellen. Globale MRSC-Tabellen replizieren geänderte Elemente synchron über Regionen hinweg und stellen so sicher, dass durch strikt konsistente Lesevorgänge in jedem Replikat immer die aktuelle Version eines Elements zurückgegeben wird. Wenn Sie eine Tabelle mit einer einzigen Region in eine globale MRSC-Tabelle konvertieren, müssen Sie sicherstellen, dass die Tabelle leer ist. Die Konvertierung einer Tabelle mit nur einer Region in eine globale MRSC-Tabelle mit vorhandenen Elementen wird nicht unterstützt. Stellen Sie sicher, dass während des Konvertierungsvorgangs keine Daten in die Tabelle geschrieben werden.

Sie können eine globale MRSC-Tabelle mit drei Replikaten oder zwei Replikaten und einem Witness konfigurieren. Beim Erstellen einer globalen MRSC-Tabelle wählen Sie die Regionen aus, in denen Replikate und ein optionaler Witness bereitgestellt werden. Im folgenden Beispiel wird eine globale MRSC-Tabelle mit Replikaten in den Regionen USA Ost (Nord-Virginia) und USA Ost (Ohio) und einem Witness in der Region USA West (Oregon) erstellt.

Anmerkung

Stellen Sie vor dem Erstellen einer globalen Tabelle sicher, dass die Service-Quota-Durchsatzgrenzwerte in allen Zielregionen einheitlich sind, da dies für die Erstellung einer globalen Tabelle erforderlich ist. Weitere Informationen zu den Grenzwerten für den Durchsatz für globale Tabellen finden Sie unter Globale Tabellenkontingente.

Gehen Sie wie folgt vor, um eine globale Tabelle mit der AWS-Managementkonsole zu erstellen.

  1. Melden Sie sich bei AWS-Managementkonsole an und öffnen Sie die DynamoDB-Konsole unter https://console.aws.amazon.com/dynamodb/.

  2. Wählen Sie in der Navigationsleiste Regionsauswahl eine Region aus, in der globale Tabellen mit MRSC unterstützt werden, wie z. B. us-east-2.

  3. Wählen Sie im Navigationsbereich Tables (Tabellen) aus.

  4. Wählen Sie Create table aus.

  5. Gehen Sie auf der Seite Tabelle erstellen wie folgt vor:

    1. Geben Sie unter Tabellenname Music ein.

    2. Geben Sie unter Partitionsschlüssel den Wert Artist ein und behalten Sie die Standardeinstellung Zeichenfolge bei.

    3. Geben Sie unter Sortierschlüssel den Wert SongTitle ein und behalten Sie die Standardeinstellung Zeichenfolge bei.

    4. Behalten Sie die übrigen Standardeinstellungen bei und wählen Sie Tabelle erstellen aus.

      Diese neue Tabelle dient als erste Replikattabelle in einer neuen globalen Tabelle. Sie stellt den Prototyp für andere Replikattabellen dar, die Sie später hinzufügen.

  6. Warten Sie, bis die Tabelle aktiv wird, und wählen Sie sie dann aus der Tabellenliste aus.

  7. Wählen Sie die Registerkarte Globale Tabellen und anschließend Replikat erstellen aus.

  8. Gehen Sie auf der Seite Replikat erstellen wie folgt vor:

    1. Wählen Sie unter Multiregionale Konsistenz die Option Starke Konsistenz aus.

    2. Wählen Sie unter Replikationsregion 1 die Option US East (N. Virginia) us-east-1 aus.

    3. Wählen Sie unter Replikationsregion 2 die Option US West (Oregon) us-west-2 aus.

    4. Aktivieren Sie Option Als Witness konfigurieren für die Region „USA West (Oregon)“.

    5. Wählen Sie die Option Replikat erstellen aus.

  9. Warten Sie, bis der Vorgang zur Erstellung des Replikats und des Witness abgeschlossen ist. Der Replikatstatus lautet Aktiv, wenn die Tabelle einsatzbereit ist.

Bevor Sie beginnen, stellen Sie sicher, dass Ihr IAM-Prinzipal über die erforderlichen Berechtigungen verfügt, um eine globale MRSC-Tabelle mit einer Witness-Region zu erstellen.

Mit der folgenden IAM-Beispielrichtlinie können Sie eine DynamoDB-Tabelle (MusicTable) in der Region „USA Ost (Ohio)“ mit einem Replikat in der Region „USA Ost (Nord-Virginia)“ und einer Witness-Region in der Region „USA West (Oregon)“ erstellen:

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" } } } ] }

In den folgenden Codebeispielen wird gezeigt, wie globale DynamoDB-Tabellen mit Multi-Region Strong Consistency (MRSC) erstellt und verwaltet werden.

  • Erstellen Sie eine Tabelle mit Multi-Region Strong Consistency.

  • Überprüfen Sie die MRSC-Konfiguration und den Replikatstatus.

  • Testen Sie die starke Konsistenz in allen Regionen mit sofortigen Lesevorgängen.

  • Führen Sie bedingte Schreibvorgänge mit MRSC-Garantien durch.

  • Bereinigen Sie die globalen MRSC-Tabellenressourcen.

Bash
AWS CLI mit Bash-Skript

Erstellen Sie eine Tabelle mit Multi-Region Strong Consistency.

# 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

Überprüfen Sie die MRSC-Konfiguration und den Replikatstatus.

# 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}}'

Testen Sie die starke Konsistenz mit sofortigen Lesevorgängen regionsübergreifend.

# 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

Führen Sie bedingte Schreibvorgänge mit MRSC-Garantien durch.

# 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

Bereinigen Sie die globalen MRSC-Tabellenressourcen.

# 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 für Java 2.x

Erstellen Sie mit AWS SDK for Java 2.x eine regionale Tabelle, die für die MRSC-Konvertierung bereit ist.

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(); } }

Konvertieren Sie mit AWS SDK for Java 2.x eine regionale Tabelle in eine MRSC-Tabelle mit Replikaten und Witnesses.

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(); } }

Beschreiben Sie mit AWS SDK for Java 2.x eine globale MRSC-Tabellenkonfiguration.

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(); } }

Fügen Sie mit AWS SDK for Java 2.x Testelemente hinzu, um die starke Konsistenz (MRSC) zu überprüfen.

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(); } }

Lesen Sie mit AWS SDK for Java 2.x Elemente mit konsistenten Lesevorgängen aus MRSC-Replikaten.

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(); } }

Führen Sie mit AWS SDK for Java 2.x bedingte Aktualisierungen mit MRSC-Garantien durch.

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(); } }

Warten Sie mit AWS SDK for Java 2.x, bis MRSC-Replikate und Witnesses aktiv werden.

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; } }

Bereinigen Sie mit AWS SDK for Java 2.x MRSC-Replikate und Witnesses.

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(); } }

Schließen Sie die Demonstration des MRSC-Workflows mit AWS SDK for Java 2.x ab.

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; } }