Partilhar via


Migrar seu aplicativo do Amazon DynamoDB para o Azure Cosmos DB

APLICA-SE A: NoSQL

O Azure Cosmos DB é um banco de dados escalável, distribuído globalmente e totalmente gerenciado. Ele fornece acesso garantido de baixa latência aos seus dados. Para saber mais sobre o Azure Cosmos DB, consulte o artigo de visão geral . Este artigo descreve como migrar seu aplicativo .NET do DynamoDB para o Azure Cosmos DB com alterações mínimas de código.

Diferenças conceptuais

A seguir estão as principais diferenças conceituais entre o Azure Cosmos DB e o DynamoDB:

DynamoDB Azure Cosmos DB
Não aplicável Base de Dados
Tabela Coleção
Item Documento
Atributo Campo
Índice Secundário Índice Secundário
Chave primária – Chave de partição Chave de Partição
Chave Primária – Chave de Ordenação Não Necessário
Fluxo ChangeFeed
Escrever unidade de computação Unidade de solicitação (flexível, pode ser usada para leituras ou gravações)
Ler unidade de computação Unidade de solicitação (flexível, pode ser usada para leituras ou gravações)
Tabelas Globais Não é necessário. Você pode selecionar diretamente a região ao provisionar a conta do Azure Cosmos DB (você pode alterar a região mais tarde)

Diferenças estruturais

O Azure Cosmos DB tem uma estrutura JSON mais simples quando comparada à do DynamoDB. O exemplo a seguir mostra as diferenças

DynamoDB:

O objeto JSON a seguir representa o formato de dados no 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:

O seguinte objeto JSON representa o formato de dados no Azure Cosmos DB:

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

Migrar o seu código

Este artigo tem como escopo migrar o código de um aplicativo para o Azure Cosmos DB, que é o aspeto crítico da migração de banco de dados. Para ajudá-lo a reduzir a curva de aprendizado, as seções a seguir incluem uma comparação de código lado a lado entre o Amazon DynamoDB e o trecho de código equivalente do Azure Cosmos DB.

Para baixar o código-fonte, clone o seguinte repositório:

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

Pré-requisitos

  • .NET Framework 4.7.2
  • Visual Studio mais recente com a carga de trabalho de desenvolvimento do Azure. Você pode começar a usar o IDE gratuito da Comunidade do Visual Studio. Habilite a carga de trabalho de desenvolvimento do Azure durante a instalação do Visual Studio.
  • Acesso ao Azure Cosmos DB para conta NoSQL
  • Instalação local do Amazon DynamoDB
  • Java 8
  • Execute a versão para download do Amazon DynamoDB na porta 8000 (você pode alterar e configurar o código)

Configure o seu código

Adicione o seguinte "pacote NuGet" ao seu projeto:

Install-Package Microsoft.Azure.Cosmos

Estabeleça conexão

DynamoDB:

No Amazon DynamoDB, o código a seguir é usado para se conectar:

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

Azure Cosmos DB:

Para conectar o Azure Cosmos DB, atualize seu código para:

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

Otimizar a conexão no Azure Cosmos DB

Com o Azure Cosmos DB, você pode usar as seguintes opções para otimizar sua conexão:

  • ConnectionMode - Use o modo de conexão direta para se conectar aos nós de dados no serviço Azure Cosmos DB. Use o modo de gateway apenas para inicializar e armazenar em cache os endereços lógicos e atualizar as atualizações. Para obter mais informações, consulte Modos de conectividade.

  • ApplicationRegion - Esta opção é usada para definir a região replicada geograficamente preferida que é usada para interagir com o Azure Cosmos DB. Para obter mais informações, consulte distribuição global.

  • ConsistencyLevel - Esta opção é usada para substituir o nível de consistência padrão. Para obter mais informações, consulte Níveis de consistência.

  • BulkExecutionMode - Esta opção é usada para executar operações em massa definindo a propriedade AllowBulkExecution como true. Para obter mais informações, consulte importação em massa.

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

Criar o contentor

DynamoDB:

Para armazenar os dados no Amazon DynamoDB, você precisa criar a tabela primeiro. No processo de criação de tabelas; Você define o esquema, o tipo de chave e os atributos, conforme mostrado no código a seguir:

// 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:

No Amazon DynamoDB, você precisa provisionar as unidades de computação de leitura ou as unidades de computação de gravação. Enquanto no Azure Cosmos DB você especifica a taxa de transferência como Unidades de Solicitação (RU/s), que podem ser usadas para quaisquer operações dinamicamente. Os dados são organizados como banco de dados --> contêiner--> item. Você pode especificar a taxa de transferência no nível do banco de dados ou no nível da coleção, ou ambos.

Para criar um banco de dados:

await client_cosmosDB.CreateDatabaseIfNotExistsAsync(movies_table_name);

Para criar o contêiner:

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

Carregar os dados

DynamoDB:

O código a seguir mostra como carregar os dados no Amazon DynamoDB. O moviesArray consiste em uma lista de documentos JSON, então você precisa iterar e carregar o documento JSON no Amazon DynamoDB:

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:

No Azure Cosmos DB, você pode optar por transmitir e escrever com moviesContainer.CreateItemStreamAsync(). No entanto, neste exemplo, o JSON será desserializado no tipo MovieModel para demonstrar o recurso de conversão de tipo. O código é multi-threaded, que usará a arquitetura distribuída do Azure Cosmos DB e acelerará o carregamento:

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

Criar um documento

DynamoDB:

Escrever um novo documento no Amazon DynamoDB não é seguro para digitação, o exemplo a seguir usa newItem como tipo de documento:

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

Azure Cosmos DB:

O Azure Cosmos DB fornece segurança de tipo por meio do modelo de dados. Usamos o modelo de dados chamado 'MovieModel':

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

No Azure Cosmos DB newItem será MovieModel:

 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;

Ler um documento

DynamoDB:

Para ler no Amazon DynamoDB, você precisa definir primitivos:

// 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:

No entanto, com o Azure Cosmos DB a consulta é natural (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;
    }

A coleção de documentos no exemplo acima será:

  • tipo seguro
  • Forneça uma opção de consulta natural.

Atualizar um item

DynamoDB: Para atualizar o item no Amazon DynamoDB:

updateResponse = await client.UpdateItemAsync( updateRequest );

Azure Cosmos DB:

No Azure Cosmos DB, a atualização será tratada como operação Upsert que significa inserir o documento se ele não existir:

await moviesContainer.UpsertItemAsync<MovieModel>(updatedMovieModel);

Eliminar um documento

DynamoDB:

Para excluir um item no Amazon DynamoDB, você novamente precisa usar primitivos:

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:

No Azure Cosmos DB, podemos obter o documento e excluí-lo de forma assíncrona:

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

Consultar documentos

DynamoDB:

No Amazon DynamoDB, as funções de api são necessárias para consultar os dados:

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:

No Azure Cosmos DB, você pode fazer projeção e filtro dentro de uma consulta sql simples:

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'))");

Para operações de intervalo, por exemplo, 'entre', você precisa fazer uma verificação no Amazon DynamoDB:

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

No Azure Cosmos DB, você pode usar a consulta SQL e uma instrução de linha única:

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");

Eliminar um contentor

DynamoDB:

Para excluir a tabela no Amazon DynamoDB, você pode especificar:

client.DeleteTableAsync( tableName );

Azure Cosmos DB:

Para excluir a coleção no Azure Cosmos DB, você pode especificar:

await moviesContainer.DeleteContainerAsync();

Em seguida, exclua o banco de dados também, se precisar:

await cosmosDatabase.DeleteAsync();

Como você pode ver, o Azure Cosmos DB oferece suporte a consultas naturais (SQL), as operações são assíncronas e muito mais fáceis. Você pode migrar facilmente seu código complexo para o Azure Cosmos DB, que se torna mais simples após a migração.

Passos Seguintes