Nota
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
SE APLICA A: NoSQL
Azure Cosmos DB es una base de datos totalmente administrada, escalable y distribuida globalmente. Proporciona acceso de baja latencia garantizado a los datos.
En este artículo se describe cómo migrar la aplicación .NET de Amazon DynamoDB a Azure Cosmos DB con cambios mínimos en el código. Para obtener más información sobre Azure Cosmos DB, vea el artículo de información general.
Diferencias conceptuales
En la tabla siguiente se enumeran las principales diferencias conceptuales entre Azure Cosmos DB y DynamoDB:
DynamoDB | Azure Cosmos DB |
---|---|
No aplicable | Base de datos |
Tabla | Colección |
Elemento | Documento |
Atributo | Campo |
Índice secundario | Índice secundario |
Clave principal > clave de partición | Clave de partición |
Clave primaria > clave de ordenación | No es necesario |
STREAM | Fuente de cambios |
Unidad de proceso de escritura | Unidad de solicitud (flexible, se puede usar para lecturas o escrituras) |
Unidad de proceso de lectura | Unidad de solicitud (flexible, se puede usar para lecturas o escrituras) |
Tabla global | No es necesario. Puede seleccionar directamente la región al aprovisionar la cuenta de Azure Cosmos DB. (Puede cambiar la región más adelante). |
Diferencias estructurales
La estructura JSON de Azure Cosmos DB es más sencilla que la estructura JSON de DynamoDB. En el ejemplo siguiente se muestran las diferencias.
DynamoDB
El siguiente objeto JSON representa el formato de datos en 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
El siguiente objeto JSON representa el formato de datos en Azure Cosmos DB:
{
"Artist": "",
"SongTitle": "",
"AlbumTitle": "",
"Year": 9999,
"Price": 0.0,
"Genre": "",
"Tags": ""
}
Migración del código
Este artículo tiene como ámbito migrar el código de una aplicación a Azure Cosmos DB, que es un aspecto crítico de la migración de bases de datos. Para ayudarle a comprender cómo funciona el proceso de migración, en las secciones siguientes se compara el código entre Amazon DynamoDB y Azure Cosmos DB.
Para descargar el código fuente, clone el siguiente repositorio:
git clone https://github.com/Azure-Samples/DynamoDB-to-CosmosDB
Prerrequisitos
- .NET Framework 4.7.2.
- Versión más reciente de Visual Studio con la carga de trabajo de desarrollo de Azure. Puede empezar con el IDE gratuito de Visual Studio Community. Habilite la carga de trabajo de desarrollo de Azure durante la configuración de Visual Studio.
- Acceso a una cuenta de Azure Cosmos DB para NoSQL.
- Instalación local de Amazon DynamoDB.
- Java 8.
- Versión descargable de Amazon DynamoDB. Ejecútelo en el puerto 8000. (Puede cambiar y configurar el código).
Configuración del código
Agregue el siguiente paquete NuGet al proyecto:
Install-Package Microsoft.Azure.Cosmos
Establecer una conexión
DynamoDB
En Amazon DynamoDB, se usa el código siguiente para conectarse:
AmazonDynamoDBConfig addbConfig = new AmazonDynamoDBConfig() ;
addbConfig.ServiceURL = "endpoint";
try { aws_dynamodbclient = new AmazonDynamoDBClient( addbConfig ); }
Azure Cosmos DB
Para conectarse a Azure Cosmos DB, actualice el código para:
client_documentDB = new CosmosClient(
"<nosql-account-endpoint>",
tokenCredential
);
Optimización de la conexión en Azure Cosmos DB
Con Azure Cosmos DB, puede usar las siguientes opciones para optimizar la conexión:
ConnectionMode
: use el modo de conexión directa para conectarse a los nodos de datos del servicio Azure Cosmos DB. Use el modo de puerta de enlace solo para inicializar y almacenar en caché las direcciones lógicas y actualizar en las actualizaciones. Para más información, consulte Modos de conectividad del SDK de SQL de Azure Cosmos DB.ApplicationRegion
: use esta opción para establecer la región con replicación geográfica preferida para interactuar con Azure Cosmos DB. Para más información, consulte Distribución de datos globalmente con Azure Cosmos DB.ConsistencyLevel
: use esta opción para invalidar el nivel de coherencia predeterminado. Para más información, consulte Niveles de coherencia en Azure Cosmos DB.BulkExecutionMode
: Use esta opción para ejecutar operaciones masivas estableciendo la propiedadAllowBulkExecution
atrue
. Para más información, consulte Importación masiva de datos en una cuenta de Azure Cosmos DB para NoSQL mediante el SDK de .NET.client_cosmosDB = new CosmosClient(" Your connection string ",new CosmosClientOptions() { ConnectionMode=ConnectionMode.Direct, ApplicationRegion=Regions.EastUS2, ConsistencyLevel=ConsistencyLevel.Session, AllowBulkExecution=true });
Cree el contenedor.
DynamoDB
Para almacenar los datos en Amazon DynamoDB, primero debe crear la tabla. Defina el esquema, el tipo de clave y los atributos, como se muestra en el código siguiente:
// 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
En Amazon DynamoDB, debe aprovisionar las unidades de proceso de lectura y las unidades de proceso de escritura. En Azure Cosmos DB, especifique el rendimiento como unidades de solicitud por segundo (RU/s). Puede utilizar RU/s para cualquier operación de manera dinámica. Los datos se organizan como base de datos, contenedor y, después, elemento. Puede especificar el rendimiento en el nivel de base de datos, en el nivel de colección o en ambos.
Para crear una base de datos:
await client_cosmosDB.CreateDatabaseIfNotExistsAsync(movies_table_name);
Para crear un contenedor:
await cosmosDatabase.CreateContainerIfNotExistsAsync(new ContainerProperties() { PartitionKeyPath = "/" + partitionKey, Id = new_collection_name }, provisionedThroughput);
Carga de los datos
DynamoDB
En el código siguiente se muestra cómo cargar los datos en Amazon DynamoDB. El código moviesArray
enumera los documentos JSON y luego debe iterarlos y cargarlos en 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
En Azure Cosmos DB, puede optar por transmitir y escribir mediante moviesContainer.CreateItemStreamAsync()
. Sin embargo, en este ejemplo, el JSON se deserializa en el tipo MovieModel
para demostrar la capacidad de conversión de tipos. El código es multiproceso y usa la arquitectura distribuida en Azure Cosmos DB para acelerar la carga.
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);
Creación de un documento
DynamoDB
Escribir un nuevo documento en Amazon DynamoDB no garantiza la seguridad de tipo. En el ejemplo siguiente se usa newItem
como tipo de documento:
Task<Document> writeNew = moviesTable.PutItemAsync(newItem, token);
await writeNew;
Azure Cosmos DB
Azure Cosmos DB proporciona seguridad de tipos a través de un modelo de datos. En este ejemplo se usa un modelo de datos denominado 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);
}
}
En Azure Cosmos DB, newItem
es 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;
Lectura de un documento
DynamoDB
Para leer en Amazon DynamoDB, debe definir primitivas:
// 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
Con Azure Cosmos DB, la consulta es 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;
}
La colección de documentos del ejemplo anterior es segura para tipos y proporciona una opción de consulta natural.
Actualización de un elemento
DynamoDB
Para actualizar un elemento en Amazon DynamoDB:
updateResponse = await client.UpdateItemAsync( updateRequest );
Azure Cosmos DB
En Azure Cosmos DB, una actualización se trata como una Upsert
operación (es decir, se inserta el documento si no existe):
await moviesContainer.UpsertItemAsync<MovieModel>(updatedMovieModel);
Eliminar un documento
DynamoDB
Para eliminar un elemento en Amazon DynamoDB, debe volver a recurrir a los 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
En Azure Cosmos DB, puede obtener el documento y eliminarlo de forma asincrónica:
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));
}
}
Consulta de documentos
DynamoDB
En Amazon DynamoDB, se requieren funciones de API para consultar los datos:
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
En Azure Cosmos DB, puede realizar la proyección y el filtro dentro de una consulta SQL simple:
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 las operaciones de rango (por ejemplo, between
), debe realizar un examen en 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( );
En Azure Cosmos DB, puede usar una consulta SQL y una instrucción de una sola línea:
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");
Eliminación de un contenedor
DynamoDB
Para eliminar la tabla en Amazon DynamoDB, puede especificar:
client.DeleteTableAsync( tableName );
Azure Cosmos DB
Para eliminar la colección en Azure Cosmos DB, puede especificar:
await moviesContainer.DeleteContainerAsync();
A continuación, elimine también la base de datos, si es necesario:
await cosmosDatabase.DeleteAsync();
Resumen
Como se muestra en los ejemplos anteriores, Azure Cosmos DB admite consultas naturales (SQL) y las operaciones son asincrónicas. Puede migrar fácilmente el código complejo a Azure Cosmos DB. El código se vuelve más sencillo después de la migración.
Contenido relacionado
- Más información sobre la optimización del rendimiento.
- Obtenga información sobre cómo optimizar las lecturas y escrituras.
- Obtenga información sobre la supervisión en Azure Cosmos DB.