Freigeben über


Migrieren einer Anwendung von Amazon DynamoDB zu Azure Cosmos DB

GILT FÜR: NoSQL

Azure Cosmos DB ist eine skalierbare, global verteilte, vollständig verwaltete Datenbank. Sie bietet garantierten Zugriff auf Ihre Daten mit geringer Latenz.

In diesem Artikel wird beschrieben, wie Sie Ihre .NET-Anwendung von AmazonDb zu Azure Cosmos DB mit minimalen Codeänderungen migrieren. Weitere Informationen zu Azure Cosmos DB finden Sie im Artikel Übersicht.

Konzeptionelle Unterschiede

Die folgende Tabelle listet die wichtigsten konzeptionellen Unterschiede zwischen Azure Cosmos DB und DynamoDB auf.

DynamoDB Azure Cosmos DB (ein Microsoft-Datenbankdienst)
Nicht anwendbar Datenbank
Tabelle Sammlung
Element Dokument
Attribut Feld
Sekundärer Index Sekundärer Index
Primärschlüssel > Partitionsschlüssel Partitionsschlüssel
Primärschlüssel > Sortierschlüssel Nicht erforderlich
Datenstrom Änderungsfeed
Compute-Einheit für Schreibvorgänge Anforderungseinheit (flexibel, kann für Lese- und Schreibvorgänge verwendet werden)
Compute-Einheit für Lesevorgänge Anforderungseinheit (flexibel, kann für Lese- und Schreibvorgänge verwendet werden)
Globale Tabelle Nicht erforderlich. Sie können die Region direkt auswählen, während Sie das Azure Cosmos DB-Konto bereitstellen. (Sie können die Region später ändern.)

Strukturelle Unterschiede

Die JSON-Struktur von Azure Cosmos DB ist einfacher als die JSON-Struktur von DynamoDB. Das folgende Beispiel zeigt die Unterschiede.

DynamoDB

Das folgende JSON-Objekt repräsentiert das Datenformat in DynamoDB.

{
TableName: "Music",
KeySchema: [
{ 
  AttributeName: "Artist",
  KeyType: "HASH", //Partition key
},
{ 
  AttributeName: "SongTitle",
  KeyType: "RANGE" //Sort key
}
],
AttributeDefinitions: [
{ 
  AttributeName: "Artist",
  AttributeType: "S"
},
{ 
  AttributeName: "SongTitle",
  AttributeType: "S"
}
],
ProvisionedThroughput: {
  ReadCapacityUnits: 1,
  WriteCapacityUnits: 1
 }
}

Azure Cosmos DB (ein Microsoft-Datenbankdienst)

Das folgende JSON-Objekt stellt das Datenformat in Azure Cosmos DB dar:

{
"Artist": "",
"SongTitle": "",
"AlbumTitle": "",
"Year": 9999,
"Price": 0.0,
"Genre": "",
"Tags": ""
}

Migrieren Ihres Codes

Dieser Artikel bezieht sich auf die Migration des Codes einer Anwendung zu Azure Cosmos DB, was ein wichtiger Aspekt der Datenbankmigration ist. Um zu verstehen, wie der Migrationsprozess funktioniert, vergleichen die folgenden Abschnitte den Code zwischen Amazon CosmosDB und Azure Cosmos DB.

Zum Herunterladen des Quellcodes klonen Sie das folgende Repository:

git clone https://github.com/Azure-Samples/DynamoDB-to-CosmosDB

Voraussetzungen

  • .NET Framework 4.7.2
  • Neueste Version von Visual Studio mit der Azure-Entwicklungsarbeitslast. Sie können mit der kostenlosen IDE Visual Studio Community beginnen. Aktivieren Sie beim Setup von Visual Studio die Workload Azure-Entwicklung.
  • Zugriff auf ein Azure Cosmos DB für NoSQL-Konto.
  • Lokale Installation von AmazonDb.
  • Java 8.
  • Herunterladbare Version von Amazon DynamoDB. Führen Sie sie an Port 8000 aus. (Sie können den Code ändern und konfigurieren.)

Richte deinen Code ein

Fügen Sie ihrem Projekt das folgende NuGet-Paket hinzu:

Install-Package Microsoft.Azure.Cosmos

Herstellen einer Verbindung

DynamoDB

In Amazon DynamoDB verwenden Sie den folgenden Code, um eine Verbindung herzustellen:

    AmazonDynamoDBConfig addbConfig = new AmazonDynamoDBConfig() ;
        addbConfig.ServiceURL = "endpoint";
        try { aws_dynamodbclient = new AmazonDynamoDBClient( addbConfig ); }

Azure Cosmos DB (ein Microsoft-Datenbankdienst)

Aktualisieren Sie Ihren Code wie folgt, um Azure Cosmos DB zu verbinden:

client_documentDB = new CosmosClient(
    "<nosql-account-endpoint>",
    tokenCredential
);

Optimieren der Verbindung in Azure Cosmos DB

Bei Azure Cosmos DB können Sie die folgenden Optionen verwenden, um die Verbindung zu optimieren:

  • ConnectionMode: Verwenden Sie den direkten Verbindungsmodus, um eine Verbindung mit den Datenknoten im Azure Cosmos DB-Dienst herzustellen. Verwenden Sie den Gatewaymodus nur zum Initialisieren und Zwischenspeichern der logischen Adressen, und führen Sie bei Änderungen eine Aktualisierung aus. Weitere Informationen finden Sie unter Azure Cosmos DB SQL SDK-Konnektivitätsmodi.

  • ApplicationRegion: Verwenden Sie diese Option, um die bevorzugte geo-replizierte Region für die Interaktion mit Azure Cosmos DB festzulegen. Weitere Informationen finden Sie unter Verteilen von Daten auf globaler Ebene mit Azure Cosmos DB.

  • ConsistencyLevel: Verwenden Sie diese Option, um die Standardkonsistenzstufe außer Kraft zu setzen. Weitere Informationen finden Sie unter Konsistenzstufen in Azure Cosmos DB.

  • BulkExecutionMode: Verwenden Sie diese Option, um Massenvorgänge auszuführen, indem Sie die AllowBulkExecution-Eigenschaft auf true setzen. Weitere Informationen finden Sie unter Massenimport von Daten in ein Azure Cosmos DB für NoSQL-Konto mithilfe des .NET SDK.

    client_cosmosDB = new CosmosClient(" Your connection string ",new CosmosClientOptions()
    { 
      ConnectionMode=ConnectionMode.Direct,
      ApplicationRegion=Regions.EastUS2,
      ConsistencyLevel=ConsistencyLevel.Session,
      AllowBulkExecution=true  
    });
    

Erstellen des Containers

DynamoDB

Um die Daten in Amazon DynamoDB zu speichern, müssen Sie zuerst die Tabelle erstellen. Definieren Sie das Schema, den Schlüsseltyp und die Attribute, wie im folgenden Code dargestellt:

// movies_key_schema
public static List<KeySchemaElement> movies_key_schema
  = new List<KeySchemaElement>
{
  new KeySchemaElement
  {
    AttributeName = partition_key_name,
    KeyType = "HASH"
  },
  new KeySchemaElement
  {
    AttributeName = sort_key_name,
    KeyType = "RANGE"
  }
};

// key names for the Movies table
public const string partition_key_name = "year";
public const string sort_key_name      = "title";
  public const int readUnits=1, writeUnits=1; 

    // movie_items_attributes
    public static List<AttributeDefinition> movie_items_attributes
  = new List<AttributeDefinition>
{
  new AttributeDefinition
  {
    AttributeName = partition_key_name,
    AttributeType = "N"
  },
  new AttributeDefinition
  {
    AttributeName = sort_key_name,
    AttributeType = "S"
  }

CreateTableRequest  request;
CreateTableResponse response;

// Build the 'CreateTableRequest' structure for the new table
request = new CreateTableRequest
{
  TableName             = table_name,
  AttributeDefinitions  = table_attributes,
  KeySchema             = table_key_schema,
  // Provisioned-throughput settings are always required,
  // although the local test version of DynamoDB ignores them.
  ProvisionedThroughput = new ProvisionedThroughput( readUnits, writeUnits );
};

Azure Cosmos DB (ein Microsoft-Datenbankdienst)

In Amazon DynamoDB müssen Sie die Lese- und Schreibkapazitätseinheiten bereitstellen. In Azure Cosmos DB geben Sie den Durchsatz als Anforderungseinheiten pro Sekunde (RU/s) an. Sie können RU/s für alle Vorgänge dynamisch verwenden. Die Daten werden als Datenbank, Container und anschließendes Element organisiert. Sie können den Durchsatz auf Datenbankebene, auf Sammlungsebene oder beides angeben.

So erstellen Sie eine Datenbank

await client_cosmosDB.CreateDatabaseIfNotExistsAsync(movies_table_name);

So erstellen Sie einen Container:

await cosmosDatabase.CreateContainerIfNotExistsAsync(new ContainerProperties() { PartitionKeyPath = "/" + partitionKey, Id = new_collection_name }, provisionedThroughput);

Laden der Daten

DynamoDB

Der folgende Code zeigt, wie Sie die Daten in Amazon DynamoDB laden. Der moviesArray Code listet JSON-Dokumente auf, und dann müssen Sie die JSON-Dokumente durchlaufen und in AmazonDb laden.

int n = moviesArray.Count;
for( int i = 0, j = 99; i < n; i++ )
    {
  try
  {
    string itemJson = moviesArray[i].ToString();
    Document doc = Document.FromJson(itemJson);
    Task putItem = moviesTable.PutItemAsync(doc);
    if( i >= j )
    {
      j++;
      Console.Write( "{0,5:#,##0}, ", j );
      if( j % 1000 == 0 )
        Console.Write( "\n " );
      j += 99;
    }
    await putItem;

Azure Cosmos DB (ein Microsoft-Datenbankdienst)

In Azure Cosmos DB können Sie Streamen und Schreiben mithilfe von moviesContainer.CreateItemStreamAsync() durchführen. In diesem Beispiel wird JSON jedoch in den MovieModel Typ deserialisiert, um die Typumwandlungsfunktion zu veranschaulichen. Der Code ist multithreaded und verwendet die verteilte Architektur in Azure Cosmos DB, um das Laden zu beschleunigen.

List<Task> concurrentTasks = new List<Task>();
for (int i = 0, j = 99; i < n; i++)
{
  try
  {
      MovieModel doc= JsonConvert.DeserializeObject<MovieModel>(moviesArray[i].ToString());
      doc.Id = Guid.NewGuid().ToString();
      concurrentTasks.Add(moviesContainer.CreateItemAsync(doc,new PartitionKey(doc.Year)));
      {
          j++;
          Console.Write("{0,5:#,##0}, ", j);
          if (j % 1000 == 0)
              Console.Write("\n               ");
          j += 99;
      }
      
  }
  catch (Exception ex)
  {
      Console.WriteLine("\n     ERROR: Could not write the movie record #{0:#,##0}, because:\n       {1}",
                          i, ex.Message);
      operationFailed = true;
      break;
  }
}
await Task.WhenAll(concurrentTasks);

Erstellen eines Dokuments

DynamoDB

Das Schreiben eines neuen Dokuments in AmazonDb ist nicht typsicher. Im folgenden Beispiel wird newItem der Dokumenttyp verwendet:

Task<Document> writeNew = moviesTable.PutItemAsync(newItem, token);
await writeNew;

Azure Cosmos DB (ein Microsoft-Datenbankdienst)

Azure Cosmos DB bietet Typsicherheit über ein Datenmodell. In diesem Beispiel wird ein Datenmodell namens MovieModel verwendet:

public class MovieModel
{
    [JsonProperty("id")]
    public string Id { get; set; }
    [JsonProperty("title")]
    public string Title{ get; set; }
    [JsonProperty("year")]
    public int Year { get; set; }
    public MovieModel(string title, int year)
    {
        this.Title = title;
        this.Year = year;
    }
    public MovieModel()
    {

    }
    [JsonProperty("info")]
    public   MovieInfo MovieInfo { get; set; }

    internal string PrintInfo()
    {
        if(this.MovieInfo!=null)
        return            string.Format("\nMovie with title:{1}\n Year: {2}, Actors: {3}\n Directors:{4}\n Rating:{5}\n", this.Id, this.Title, this.Year, String.Join(",",this.MovieInfo.Actors), this.MovieInfo, this.MovieInfo.Rating);
        else
            return string.Format("\nMovie with  title:{0}\n Year: {1}\n",  this.Title, this.Year);
    }
}

In Azure Cosmos DB, ist newItemMovieModel:

 MovieModel movieModel = new MovieModel()
            {
                Id = Guid.NewGuid().ToString(),
                Title = "The Big New Movie",
                Year = 2018,
                MovieInfo = new MovieInfo() { Plot = "Nothing happens at all.", Rating = 0 }
            };
    var writeNew= moviesContainer.CreateItemAsync(movieModel, new Microsoft.Azure.Cosmos.PartitionKey(movieModel.Year));
    await writeNew;

Lesen eines Dokuments

DynamoDB

Zum Lesen von Amazon DynamoDB müssen Sie Primitive definieren:

// Create primitives for the HASH and RANGE portions of the primary key
Primitive hash = new Primitive(year.ToString(), true);
Primitive range = new Primitive(title, false);

  Task<Document> readMovie = moviesTable.GetItemAsync(hash, range, token);
  movie_record = await readMovie;

Azure Cosmos DB (ein Microsoft-Datenbankdienst)

Bei Azure Cosmos DB ist die Abfrage natürlich (LINQ):

IQueryable<MovieModel> movieQuery = moviesContainer.GetItemLinqQueryable<MovieModel>(true)
                        .Where(f => f.Year == year && f.Title == title);
// The query is executed synchronously here, but can also be executed asynchronously via the IDocumentQuery<T> interface
    foreach (MovieModel movie in movieQuery)
    {
      movie_record_cosmosdb = movie;
    }

Die Dokumentauflistung im vorherigen Beispiel ist typsicher und stellt eine natürliche Abfrageoption bereit.

Aktualisieren eines Elements

DynamoDB

So aktualisieren Sie ein Element in AmazonDb:

updateResponse = await client.UpdateItemAsync( updateRequest );

Azure Cosmos DB (ein Microsoft-Datenbankdienst)

In Azure Cosmos DB wird ein Update als Upsert Vorgang behandelt (d. h. fügen Sie das Dokument ein, wenn es nicht vorhanden ist):

await moviesContainer.UpsertItemAsync<MovieModel>(updatedMovieModel);

Löschen eines Dokuments

DynamoDB

Um ein Element in Amazon DynamoDB zu löschen, müssen Sie erneut auf Primitive zurückgreifen:

Primitive hash = new Primitive(year.ToString(), true);
      Primitive range = new Primitive(title, false);
      DeleteItemOperationConfig deleteConfig = new DeleteItemOperationConfig( );
      deleteConfig.ConditionalExpression = condition;
      deleteConfig.ReturnValues = ReturnValues.AllOldAttributes;
      
  Task<Document> delItem = table.DeleteItemAsync( hash, range, deleteConfig );
        deletedItem = await delItem;

Azure Cosmos DB (ein Microsoft-Datenbankdienst)

In Azure Cosmos DB können Sie das Dokument abrufen und asynchron löschen:

var result= ReadingMovieItem_async_List_CosmosDB("select * from c where c.info.rating>7 AND c.year=2018 AND c.title='The Big New Movie'");
while (result.HasMoreResults)
{
  var resultModel = await result.ReadNextAsync();
  foreach (var movie in resultModel.ToList<MovieModel>())
  {
    await moviesContainer.DeleteItemAsync<MovieModel>(movie.Id, new PartitionKey(movie.Year));
  }
  }

Abfragedokumente

DynamoDB

In Amazon DynamoDB sind API-Funktionen erforderlich, um die Daten abzufragen.

QueryOperationConfig config = new QueryOperationConfig( );
  config.Filter = new QueryFilter( );
  config.Filter.AddCondition( "year", QueryOperator.Equal, new DynamoDBEntry[ ] { 1992 } );
  config.Filter.AddCondition( "title", QueryOperator.Between, new DynamoDBEntry[ ] { "B", "Hzz" } );
  config.AttributesToGet = new List<string> { "year", "title", "info" };
  config.Select = SelectValues.SpecificAttributes;
  search = moviesTable.Query( config ); 

Azure Cosmos DB (ein Microsoft-Datenbankdienst)

In Azure Cosmos DB können Sie Projektion und Filter in einer einfachen SQL-Abfrage durchführen:

var result = moviesContainer.GetItemQueryIterator<MovieModel>( 
  "select c.Year, c.Title, c.info from c where Year=1998 AND (CONTAINS(Title,'B') OR CONTAINS(Title,'Hzz'))");

Für Bereichsvorgänge wie between müssen Sie einen Scan in Amazon DynamoDB durchführen:

ScanRequest sRequest = new ScanRequest
{
  TableName = "Movies",
  ExpressionAttributeNames = new Dictionary<string, string>
  {
    { "#yr", "year" }
  },
  ExpressionAttributeValues = new Dictionary<string, AttributeValue>
  {
      { ":y_a", new AttributeValue { N = "1960" } },
      { ":y_z", new AttributeValue { N = "1969" } },
  },
  FilterExpression = "#yr between :y_a and :y_z",
  ProjectionExpression = "#yr, title, info.actors[0], info.directors, info.running_time_secs"
};

ClientScanning_async( sRequest ).Wait( );

In Azure Cosmos DB können Sie eine SQL-Abfrage und eine einzeilige Anweisung verwenden:

var result = moviesContainer.GetItemQueryIterator<MovieModel>( 
  "select c.title, c.info.actors[0], c.info.directors,c.info.running_time_secs from c where BETWEEN year 1960 AND 1969");

Löschen eines Containers

DynamoDB

Zum Löschen der Tabelle in Amazon DynamoDB können Sie Folgendes angeben:

client.DeleteTableAsync( tableName );

Azure Cosmos DB (ein Microsoft-Datenbankdienst)

Zum Löschen der Sammlung in Azure Cosmos DB können Sie Folgendes angeben:

await moviesContainer.DeleteContainerAsync();

Löschen Sie die Datenbank bei Bedarf auch:

await cosmosDatabase.DeleteAsync();

Zusammenfassung

Wie die vorstehenden Beispiele zeigen, unterstützt Azure Cosmos DB natürliche Abfragen (SQL), und Vorgänge sind asynchron. Sie können Ihren komplexen Code ganz einfach zu Azure Cosmos DB migrieren. Der Code wird nach der Migration einfacher.