Migrera ditt program från Amazon DynamoDB till Azure Cosmos DB
GÄLLER FÖR: NoSQL
Azure Cosmos DB är en skalbar, globalt distribuerad, fullständigt hanterad databas. Det ger garanterad åtkomst till dina data med låg latens. Mer information om Azure Cosmos DB finns i översiktsartikeln. Den här artikeln beskriver hur du migrerar .NET-programmet från DynamoDB till Azure Cosmos DB med minimala kodändringar.
Begreppsmässiga skillnader
Följande är de viktigaste begreppsmässiga skillnaderna mellan Azure Cosmos DB och DynamoDB:
DynamoDB | Azure Cosmos DB |
---|---|
Inte tillämpligt | Databas |
Register | Samling |
Artikel | Dokument |
Attribut | Fält |
Sekundärt index | Sekundärt index |
Primärnyckel – partitionsnyckel | Partition Key (Partitionsnyckel) |
Primärnyckel – sorteringsnyckel | Krävs inte |
Stream | ChangeFeed |
Skriv beräkningsenhet | Begärandeenhet (flexibel, kan användas för läsningar eller skrivningar) |
Läs beräkningsenhet | Begärandeenhet (flexibel, kan användas för läsningar eller skrivningar) |
Globala tabeller | Krävs inte. Du kan välja regionen direkt när du etablerar Azure Cosmos DB-kontot (du kan ändra regionen senare) |
Strukturella skillnader
Azure Cosmos DB har en enklare JSON-struktur jämfört med DynamoDB. I följande exempel visas skillnaderna
DynamoDB:
Följande JSON-objekt representerar dataformatet i 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:
Följande JSON-objekt representerar dataformatet i Azure Cosmos DB
{
"Artist": "",
"SongTitle": "",
"AlbumTitle": "",
"Year": 9999,
"Price": 0.0,
"Genre": "",
"Tags": ""
}
Migrera din kod
Den här artikeln är begränsad till att migrera ett programs kod till Azure Cosmos DB, vilket är den kritiska aspekten av databasmigreringen. För att minska inlärningskurvan innehåller följande avsnitt en kodjämförelse sida vid sida mellan Amazon DynamoDB och Motsvarande kodfragment i Azure Cosmos DB.
Om du vill ladda ned källkoden klonar du följande lagringsplats:
git clone https://github.com/Azure-Samples/DynamoDB-to-CosmosDB
Förutsättningar
- .NET Framework 4.7.2
- Senaste Visual Studio med Azure-utvecklingsarbetsbelastningen. Du kan komma igång med den kostnadsfria Visual Studio Community IDE. Aktivera arbetsbelastningen Azure-utveckling under Visual Studio-installationen.
- Åtkomst till Azure Cosmos DB för NoSQL-konto
- Lokal installation av Amazon DynamoDB
- Java 8
- Kör den nedladdningsbara versionen av Amazon DynamoDB på port 8000 (du kan ändra och konfigurera koden)
Konfigurera din kod
Lägg till följande "NuGet-paket" i projektet:
Install-Package Microsoft.Azure.Cosmos
Upprätta anslutning
DynamoDB:
I Amazon DynamoDB används följande kod för att ansluta:
AmazonDynamoDBConfig addbConfig = new AmazonDynamoDBConfig() ;
addbConfig.ServiceURL = "endpoint";
try { aws_dynamodbclient = new AmazonDynamoDBClient( addbConfig ); }
Azure Cosmos DB:
Om du vill ansluta Azure Cosmos DB uppdaterar du koden till:
client_documentDB = new CosmosClient(
"<nosql-account-endpoint>",
tokenCredential
);
Optimera anslutningen i Azure Cosmos DB
Med Azure Cosmos DB kan du använda följande alternativ för att optimera anslutningen:
ConnectionMode – Använd direktanslutningsläge för att ansluta till datanoderna i Azure Cosmos DB-tjänsten. Använd endast gatewayläge för att initiera och cachelagra de logiska adresserna och uppdatera vid uppdateringar. Mer information finns i anslutningslägen.
ApplicationRegion – Det här alternativet används för att ange önskad geo-replikerad region som används för att interagera med Azure Cosmos DB. Mer information finns i global distribution.
ConsistencyLevel – Det här alternativet används för att åsidosätta standardkonsekvensnivån. Mer information finns i konsekvensnivåer.
BulkExecutionMode – Det här alternativet används för att köra massåtgärder genom att ange egenskapen AllowBulkExecution till true. Mer information finns i massimport.
client_cosmosDB = new CosmosClient(" Your connection string ",new CosmosClientOptions() { ConnectionMode=ConnectionMode.Direct, ApplicationRegion=Regions.EastUS2, ConsistencyLevel=ConsistencyLevel.Session, AllowBulkExecution=true });
Skapa containern
DynamoDB:
Om du vill lagra data i Amazon DynamoDB måste du skapa tabellen först. I processen för att skapa tabellen; du definierar schemat, nyckeltypen och attributen enligt följande kod:
// 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:
I Amazon DynamoDB måste du etablera läsbearbetningsenheterna och beräkningsenheterna för skrivning. I Azure Cosmos DB anger du dataflödet som enheter för begäran (RU/s) som kan användas för alla åtgärder dynamiskt. Data ordnas som databas –> container –> objekt. Du kan ange dataflödet på databasnivå eller på samlingsnivå eller båda.
Så här skapar du en databas:
await client_cosmosDB.CreateDatabaseIfNotExistsAsync(movies_table_name);
Så här skapar du containern:
await cosmosDatabase.CreateContainerIfNotExistsAsync(new ContainerProperties() { PartitionKeyPath = "/" + partitionKey, Id = new_collection_name }, provisionedThroughput);
Läsa in data
DynamoDB:
Följande kod visar hur du läser in data i Amazon DynamoDB. MoviesArray består av en lista över JSON-dokument och sedan måste du iterera igenom och läsa in JSON-dokumentet i 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:
I Azure Cosmos DB kan du välja stream och skriva med moviesContainer.CreateItemStreamAsync()
. I det här exemplet kommer JSON dock att deserialiseras till typen MovieModel för att demonstrera typgjutningsfunktionen. Koden är flertrådad, som använder Azure Cosmos DB:s distribuerade arkitektur och påskyndar inläsningen:
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);
Skapa ett dokument
DynamoDB:
Att skriva ett nytt dokument i Amazon DynamoDB är inte typsäkert. I följande exempel används newItem som dokumenttyp:
Task<Document> writeNew = moviesTable.PutItemAsync(newItem, token);
await writeNew;
Azure Cosmos DB:
Azure Cosmos DB ger dig typsäkerhet via datamodell. Vi använder datamodellen "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);
}
}
I Azure Cosmos DB blir 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;
Läsa ett dokument
DynamoDB:
Om du vill läsa i Amazon DynamoDB måste du definiera primitiver:
// 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:
Med Azure Cosmos DB är frågan dock naturlig (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;
}
Dokumentsamlingen i exemplet ovan är:
- typsäker
- ge ett naturligt frågealternativ.
Uppdatera ett objekt
DynamoDB: Så här uppdaterar du objektet i Amazon DynamoDB:
updateResponse = await client.UpdateItemAsync( updateRequest );
Azure Cosmos DB:
I Azure Cosmos DB behandlas uppdateringen som Upsert-åtgärd, vilket innebär att infoga dokumentet om det inte finns:
await moviesContainer.UpsertItemAsync<MovieModel>(updatedMovieModel);
Ta bort ett dokument
DynamoDB:
Om du vill ta bort ett objekt i Amazon DynamoDB måste du återigen använda primitiver:
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:
I Azure Cosmos DB kan vi hämta dokumentet och ta bort dem asynkront:
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));
}
}
Köra en fråga mot dokument
DynamoDB:
I Amazon DynamoDB krävs API-funktioner för att köra frågor mot data:
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:
I Azure Cosmos DB kan du göra projektion och filtrera i en enkel SQL-fråga:
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 intervallåtgärder, till exempel "mellan", måste du göra en genomsökning i 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( );
I Azure Cosmos DB kan du använda SQL-fråga och en enrads-instruktion:
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");
Ta bort en container
DynamoDB:
Om du vill ta bort tabellen i Amazon DynamoDB kan du ange:
client.DeleteTableAsync( tableName );
Azure Cosmos DB:
Om du vill ta bort samlingen i Azure Cosmos DB kan du ange:
await moviesContainer.DeleteContainerAsync();
Ta sedan även bort databasen om du behöver:
await cosmosDatabase.DeleteAsync();
Som du ser stöder Azure Cosmos DB naturliga frågor (SQL), åtgärder är asynkrona och mycket enklare. Du kan enkelt migrera din komplexa kod till Azure Cosmos DB, vilket blir enklare efter migreringen.
Nästa steg
- Lär dig mer om prestandaoptimering.
- Lär dig mer om att optimera läsningar och skrivningar
- Läs mer om övervakning i Azure Cosmos DB