Migrowanie aplikacji z bazy danych Amazon DynamoDB do usługi Azure Cosmos DB
DOTYCZY: NoSQL
Azure Cosmos DB to skalowalna, globalnie rozproszona, w pełni zarządzana baza danych. Zapewnia gwarantowany dostęp do danych z małym opóźnieniem. Aby dowiedzieć się więcej na temat usługi Azure Cosmos DB, zobacz artykuł z omówieniem. W tym artykule opisano sposób migrowania aplikacji .NET z bazy danych DynamoDB do usługi Azure Cosmos DB z minimalnymi zmianami kodu.
Różnice koncepcyjne
Poniżej przedstawiono kluczowe różnice koncepcyjne między usługą Azure Cosmos DB i bazą danych DynamoDB:
DynamoDB | Azure Cosmos DB |
---|---|
Nie dotyczy | baza danych |
Table | Kolekcja |
Towar | Dokument |
Atrybut | Pole |
Indeks pomocniczy | Indeks pomocniczy |
Klucz podstawowy — klucz partycji | Klucz partycji |
Klucz podstawowy — klucz sortowania | Niewymagane |
Stream | Zmieńfeed |
Pisanie jednostki obliczeniowej | Jednostka żądania (elastyczna, może służyć do odczytu lub zapisu) |
Odczyt jednostki obliczeniowej | Jednostka żądania (elastyczna, może służyć do odczytu lub zapisu) |
Tabele globalne | Niewymagane. Możesz bezpośrednio wybrać region podczas aprowizowania konta usługi Azure Cosmos DB (możesz później zmienić region) |
Różnice strukturalne
Usługa Azure Cosmos DB ma prostszą strukturę JSON w porównaniu z bazą danych DynamoDB. W poniższym przykładzie przedstawiono różnice
DynamoDB:
Poniższy obiekt JSON reprezentuje format danych w bazie danych 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:
Poniższy obiekt JSON reprezentuje format danych w usłudze Azure Cosmos DB
{
"Artist": "",
"SongTitle": "",
"AlbumTitle": "",
"Year": 9999,
"Price": 0.0,
"Genre": "",
"Tags": ""
}
Migrowanie kodu
Ten artykuł obejmuje migrowanie kodu aplikacji do usługi Azure Cosmos DB, co jest krytycznym aspektem migracji bazy danych. Aby ułatwić zmniejszenie krzywej uczenia się, poniższe sekcje zawierają porównanie kodu równoległego między bazą danych Amazon DynamoDB i równoważnym fragmentem kodu usługi Azure Cosmos DB.
Aby pobrać kod źródłowy, sklonuj następujące repozytorium:
git clone https://github.com/Azure-Samples/DynamoDB-to-CosmosDB
Wymagania wstępne
- .NET Framework 4.7.2
- Najnowsza wersja programu Visual Studio z pakietem roboczym Programowanie na platformie Azure. Możesz rozpocząć pracę z bezpłatnym środowiskiem IDE programu Visual Studio Community . Włącz obciążenie programowanie na platformie Azure podczas konfigurowania programu Visual Studio.
- Dostęp do konta usługi Azure Cosmos DB for NoSQL
- Lokalna instalacja bazy danych Amazon DynamoDB
- Java 8
- Uruchom pobraną wersję bazy danych Amazon DynamoDB na porcie 8000 (można zmienić i skonfigurować kod)
Konfigurowanie kodu
Dodaj następujący element "Pakiet NuGet" do projektu:
Install-Package Microsoft.Azure.Cosmos
Nawiązywanie połączenia
DynamoDB:
W usłudze Amazon DynamoDB do nawiązania połączenia służy następujący kod:
AmazonDynamoDBConfig addbConfig = new AmazonDynamoDBConfig() ;
addbConfig.ServiceURL = "endpoint";
try { aws_dynamodbclient = new AmazonDynamoDBClient( addbConfig ); }
Azure Cosmos DB:
Aby połączyć usługę Azure Cosmos DB, zaktualizuj kod do:
client_documentDB = new CosmosClient(
"<nosql-account-endpoint>",
tokenCredential
);
Optymalizowanie połączenia w usłudze Azure Cosmos DB
Za pomocą usługi Azure Cosmos DB możesz użyć następujących opcji, aby zoptymalizować połączenie:
ConnectionMode — użyj trybu bezpośredniego połączenia, aby nawiązać połączenie z węzłami danych w usłudze Azure Cosmos DB. Użyj trybu bramy tylko do inicjowania i buforowania adresów logicznych i odświeżania aktualizacji. Aby uzyskać więcej informacji, zobacz tryby łączności.
ApplicationRegion — ta opcja służy do ustawiania preferowanego regionu replikowanego geograficznie, który jest używany do interakcji z usługą Azure Cosmos DB. Aby uzyskać więcej informacji, zobacz Dystrybucja globalna.
ConsistencyLevel — ta opcja służy do zastępowania domyślnego poziomu spójności. Aby uzyskać więcej informacji, zobacz poziomy spójności.
BulkExecutionMode — ta opcja służy do wykonywania operacji zbiorczych przez ustawienie właściwości AllowBulkExecution na wartość true. Aby uzyskać więcej informacji, zobacz importowanie zbiorcze.
client_cosmosDB = new CosmosClient(" Your connection string ",new CosmosClientOptions() { ConnectionMode=ConnectionMode.Direct, ApplicationRegion=Regions.EastUS2, ConsistencyLevel=ConsistencyLevel.Session, AllowBulkExecution=true });
Tworzenie kontenera
DynamoDB:
Aby zapisać dane w bazie danych Amazon DynamoDB, musisz najpierw utworzyć tabelę. W procesie tworzenia tabeli; należy zdefiniować schemat, typ klucza i atrybuty, jak pokazano w poniższym kodzie:
// 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:
W usłudze Amazon DynamoDB należy aprowizować jednostki obliczeniowe odczytu i jednostki obliczeniowe zapisu. Podczas gdy w usłudze Azure Cosmos DB określasz przepływność jako jednostki żądań (RU/s), która może być używana w przypadku dowolnych operacji dynamicznie. Dane są zorganizowane jako baza danych —> kontener —> element. Przepływność można określić na poziomie bazy danych lub na poziomie kolekcji lub obu tych poziomach.
Aby utworzyć bazę danych:
await client_cosmosDB.CreateDatabaseIfNotExistsAsync(movies_table_name);
Aby utworzyć kontener:
await cosmosDatabase.CreateContainerIfNotExistsAsync(new ContainerProperties() { PartitionKeyPath = "/" + partitionKey, Id = new_collection_name }, provisionedThroughput);
Ładowanie danych
DynamoDB:
Poniższy kod pokazuje, jak załadować dane w usłudze Amazon DynamoDB. Aplikacja moviesArray składa się z listy dokumentów JSON, a następnie należy wykonać iterację i załadować dokument JSON do bazy danych 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:
W usłudze Azure Cosmos DB możesz wybrać opcję przesyłania strumieniowego i zapisu za pomocą polecenia moviesContainer.CreateItemStreamAsync()
. Jednak w tym przykładzie kod JSON zostanie zdeserializowany do typu MovieModel , aby zademonstrować funkcję rzutowania typów. Kod jest wielowątkowy, który będzie używać rozproszonej architektury usługi Azure Cosmos DB i przyspieszyć ładowanie:
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);
Tworzenie dokumentu
DynamoDB:
Pisanie nowego dokumentu w bazie danych Amazon DynamoDB nie jest bezpieczne. W poniższym przykładzie jako typ dokumentu użyto elementu newItem:
Task<Document> writeNew = moviesTable.PutItemAsync(newItem, token);
await writeNew;
Azure Cosmos DB:
Usługa Azure Cosmos DB zapewnia bezpieczeństwo typów za pośrednictwem modelu danych. Używamy modelu danych o nazwie "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);
}
}
W usłudze Azure Cosmos DB newItem będzie 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;
Odczytywanie dokumentu
DynamoDB:
Aby przeczytać w bazie danych Amazon DynamoDB, należy zdefiniować elementy pierwotne:
// 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:
Jednak w przypadku usługi Azure Cosmos DB zapytanie jest naturalne (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;
}
Kolekcja dokumentów w powyższym przykładzie będzie:
- bezpieczny typ
- podaj naturalną opcję zapytania.
Aktualizowanie elementu
DynamoDB: Aby zaktualizować element w bazie danych Amazon DynamoDB:
updateResponse = await client.UpdateItemAsync( updateRequest );
Azure Cosmos DB:
W usłudze Azure Cosmos DB aktualizacja będzie traktowana jako operacja Upsert, co oznacza wstawienie dokumentu, jeśli nie istnieje:
await moviesContainer.UpsertItemAsync<MovieModel>(updatedMovieModel);
Usuwanie dokumentu
DynamoDB:
Aby usunąć element w bazie danych Amazon DynamoDB, należy ponownie spaść na elementy pierwotne:
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:
W usłudze Azure Cosmos DB możemy pobrać dokument i usunąć je asynchronicznie:
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));
}
}
Dokumenty z zapytaniami
DynamoDB:
W usłudze Amazon DynamoDB funkcje interfejsu API są wymagane do wykonywania zapytań dotyczących danych:
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:
W usłudze Azure Cosmos DB można wykonywać projekcję i filtrować wewnątrz prostego zapytania SQL:
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'))");
W przypadku operacji zakresu, na przykład "między", należy przeprowadzić skanowanie w bazie danych 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( );
W usłudze Azure Cosmos DB można użyć zapytania SQL i instrukcji jednowierszowej:
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");
Usuwanie kontenera
DynamoDB:
Aby usunąć tabelę w bazie danych Amazon DynamoDB, możesz określić:
client.DeleteTableAsync( tableName );
Azure Cosmos DB:
Aby usunąć kolekcję w usłudze Azure Cosmos DB, możesz określić:
await moviesContainer.DeleteContainerAsync();
Następnie usuń bazę danych również, jeśli potrzebujesz:
await cosmosDatabase.DeleteAsync();
Jak widać, usługa Azure Cosmos DB obsługuje zapytania naturalne (SQL), operacje są asynchroniczne i znacznie łatwiejsze. Możesz łatwo migrować złożony kod do usługi Azure Cosmos DB, co staje się prostsze po migracji.
Następne kroki
- Dowiedz się więcej o optymalizacji wydajności.
- Dowiedz się więcej o optymalizacji odczytów i zapisów
- Dowiedz się więcej o monitorowaniu w usłudze Azure Cosmos DB