Compartilhar via


Migre seu aplicativo do Amazon DynamoDB para o Azure Cosmos DB

APLICA-SE A: NoSQL

O Azure Cosmos DB é um banco de dados escalonável, distribuído globalmente e totalmente gerenciado. Ele fornece acesso de baixa latência garantido aos seus dados.

Este artigo descreve como migrar seu aplicativo .NET do Amazon DynamoDB para o Azure Cosmos DB com alterações mínimas de código. Para saber mais sobre o Azure Cosmos DB, veja o artigo de visão geral.

Diferenças conceituais

A tabela a seguir lista as principais diferenças conceituais entre o Azure Cosmos DB e o DynamoDB:

DynamoDB Azure Cosmos DB
Não aplicável Banco 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 classificação Não é necessário
Stream Feed de alteração
Unidade de computação de gravação Unidade de solicitação (flexível, pode ser usada para leituras ou gravações)
Unidade de computação de leitura Unidade de solicitação (flexível, pode ser usada para leituras ou gravações)
Tabela global Não necessário. Você pode selecionar diretamente a região durante o provisionamento da conta do Azure Cosmos DB. (Você pode alterar a região mais tarde.)

Diferenças estruturais

A estrutura JSON do Azure Cosmos DB é mais simples do que a estrutura JSON do DynamoDB. O exemplo a seguir mostra as diferenças.

DynamoDB

O seguinte objeto JSON 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 seu código

Este artigo tem o escopo de migrar o código de um aplicativo para o Azure Cosmos DB, que é um aspecto crítico da migração de banco de dados. Para ajudá-lo a entender como o processo de migração funciona, as seções a seguir comparam o código entre o Amazon DynamoDB e o 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.
  • Versão mais recente do Visual Studio com a carga de trabalho de desenvolvimento do Azure. Você pode começar com 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 a uma conta do Azure Cosmos DB para NoSQL.
  • Instalação local do Amazon DynamoDB.
  • Java 8.
  • Versão para download do Amazon DynamoDB. Execute-o na porta 8000. (Você pode alterar e configurar o código.)

Configurar seu código

Adicione o seguinte pacote NuGet ao seu projeto:

Install-Package Microsoft.Azure.Cosmos

Estabelecer uma conexão

DynamoDB

No Amazon DynamoDB, você usa o seguinte código 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 do Azure Cosmos DB. Use o modo somente gateway para inicializar e armazenar em cache os endereços lógicos e atualizações nas atualizações. Para obter mais informações, consulte os modos de conectividade do SDK do SQL do Azure Cosmos DB.

  • ApplicationRegion: use essa opção para definir a região replicada geográfica preferencial para interagir com o Azure Cosmos DB. Para obter mais informações, confira o artigo Distribuir seus dados globalmente com o Azure Cosmos DB.

  • ConsistencyLevel: use essa opção para substituir o nível de consistência padrão. Para obter mais informações, consulte os níveis de consistência no Azure Cosmos DB.

  • BulkExecutionMode: use esta opção para executar operações em massa definindo a AllowBulkExecution propriedade como true. Para obter mais informações, consulte Importação de dados em massa para uma conta do Azure Cosmos DB NoSQL usando o SDK .NET.

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

Criar o contêiner

DynamoDB

Para armazenar os dados no Amazon DynamoDB, você precisa criar a tabela primeiro. Defina o esquema, o tipo de chave e os atributos, conforme mostrado no seguinte código:

// 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 e as unidades de computação de gravação. No Azure Cosmos DB, especifique a taxa de transferência como unidades de solicitação por segundo (RU/s). Você pode usar RU/s para qualquer operação dinamicamente. Os dados são organizados como banco de dados, contêiner e item. Você pode especificar a taxa de transferência no nível do banco de dados, no nível da coleção ou em ambos.

Para criar um banco de dados:

await client_cosmosDB.CreateDatabaseIfNotExistsAsync(movies_table_name);

Para criar um 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 código lista documentos JSON e, em seguida, você precisa iterar e carregar os documentos 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 gravar usando moviesContainer.CreateItemStreamAsync(). No entanto, neste exemplo, o JSON é desserializado para o tipo MovieModel para demonstrar a funcionalidade de conversão de tipo. O código é multithreaded e usa a arquitetura distribuída no Azure Cosmos DB para 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 é tipo seguro. O exemplo a seguir usa newItem como o tipo de documento:

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

Azure Cosmos DB (Banco de Dados Cosmos da Azure)

O Azure Cosmos DB fornece segurança de tipo por meio de um modelo de dados. Este exemplo usa um 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 é 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 o 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

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 anterior é segura em termos de tipo e fornece uma opção de consulta natural.

Atualizar um item

DynamoDB

Para atualizar um item no Amazon DynamoDB:

updateResponse = await client.UpdateItemAsync( updateRequest );

Azure Cosmos DB

No Azure Cosmos DB, uma atualização é tratada como Upsert operação (ou seja, insira o documento se ele não existir):

await moviesContainer.UpsertItemAsync<MovieModel>(updatedMovieModel);

Excluir um documento

DynamoDB

Para excluir um item no Amazon DynamoDB, você precisará recorrer aos métodos básicos novamente:

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, você pode 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 filtrar 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, between), 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 uma 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");

Excluir um contêiner

DynamoDB

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

client.DeleteTableAsync( tableName );

Azure Cosmos DB (Banco de Dados da Azure Cosmos)

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 necessário:

await cosmosDatabase.DeleteAsync();

Resumo

Como mostram os exemplos anteriores, o Azure Cosmos DB dá suporte a consultas naturais (SQL) e as operações são assíncronas. Você pode migrar facilmente seu código complexo para o Azure Cosmos DB. O código fica mais simples após a migração.