적용 대상: NoSQL
Azure Cosmos DB는 확장 가능하고 전 세계적으로 분산되고 완전히 관리되는 데이터베이스입니다. 데이터에 대한 짧은 대기 시간 액세스를 보장합니다.
이 문서에서는 최소한의 코드 변경으로 Amazon DynamoDB에서 Azure Cosmos DB로 .NET 애플리케이션을 마이그레이션하는 방법을 설명합니다. Azure Cosmos DB에 대한 자세한 내용은 개요 문서를 참조하세요.
개념적 차이점
다음 표에서는 Azure Cosmos DB와 DynamoDB의 주요 개념적 차이점을 나열합니다.
DynamoDB | Azure Cosmos DB (애저 코스모스 DB) |
---|---|
해당 없음 | 데이터베이스 |
테이블 | 컬렉션 |
항목 | 문서 |
특성 | 필드 |
보조 인덱스 | 보조 인덱스 |
기본 키 > 파티션 키 | 파티션 키 |
기본 키 > 정렬 키 | 필요하지 않음 |
STREAM | 변경 피드 |
쓰기 컴퓨팅 단위 | 요청 단위(유연, 읽기 또는 쓰기에 사용할 수 있음) |
읽기 컴퓨팅 단위 | 요청 단위(유연, 읽기 또는 쓰기에 사용할 수 있음) |
글로벌 테이블 | 필수 아님. Azure Cosmos DB 계정을 프로비전하는 동안 지역을 직접 선택할 수 있습니다. (나중에 지역을 변경할 수 있습니다.) |
구조적 차이점
Azure Cosmos DB의 JSON 구조는 DynamoDB의 JSON 구조보다 단순합니다. 다음 예제는 차이점을 보여 줍니다.
DynamoDB
다음 JSON 개체는 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 (애저 코스모스 DB)
다음 JSON 개체는 Azure Cosmos DB의 데이터 형식을 나타냅니다.
{
"Artist": "",
"SongTitle": "",
"AlbumTitle": "",
"Year": 9999,
"Price": 0.0,
"Genre": "",
"Tags": ""
}
코드 마이그레이션
이 문서는 애플리케이션의 코드를 Azure Cosmos DB로 마이그레이션하는 과정을 다룹니다. 이 과정은 데이터베이스 마이그레이션의 중요한 측면입니다. 마이그레이션 프로세스가 작동하는 방식을 이해하는 데 도움이 되도록 다음 섹션에서는 Amazon DynamoDB와 Azure Cosmos DB의 코드를 비교합니다.
소스 코드를 다운로드하려면 다음 리포지토리를 복제합니다.
git clone https://github.com/Azure-Samples/DynamoDB-to-CosmosDB
필수 조건
- .NET Framework 4.7.2.
- Azure 개발 워크로드를 지원하는 최신 버전의 Visual Studio. 무료Visual Studio Community IDE로 시작할 수 있습니다. Visual Studio 설정 중에 Azure 개발 워크로드를 사용하도록 설정합니다.
- Azure Cosmos DB for NoSQL 계정에 대한 액세스.
- Amazon DynamoDB의 로컬 설치.
- Java 8.
- Amazon DynamoDB의 다운로드 가능한 버전입니다. 포트 8000에서 실행합니다. (코드를 변경하고 구성할 수 있습니다.)
코드 설정
다음 "NuGet 패키지"를 프로젝트에 추가합니다.
Install-Package Microsoft.Azure.Cosmos
연결 설정
DynamoDB
Amazon DynamoDB에서는 다음 코드를 사용하여 연결합니다.
AmazonDynamoDBConfig addbConfig = new AmazonDynamoDBConfig() ;
addbConfig.ServiceURL = "endpoint";
try { aws_dynamodbclient = new AmazonDynamoDBClient( addbConfig ); }
Azure Cosmos DB (애저 코스모스 DB)
Azure Cosmos DB 연결하려면 코드를 다음으로 업데이트합니다.
client_documentDB = new CosmosClient(
"<nosql-account-endpoint>",
tokenCredential
);
Azure Cosmos DB에서 연결 최적화
Azure Cosmos DB를 사용하여 다음 옵션을 사용하여 연결을 최적화할 수 있습니다.
ConnectionMode
: Azure Cosmos DB 서비스의 데이터 노드에 연결하려면 직접 연결 모드를 사용합니다. 게이트웨이 모드를 사용하여 논리적 주소를 초기화 및 캐시하고 업데이트 시 새로 고칩니다. 자세한 내용은 Azure Cosmos DB SQL SDK 연결 모드를 참조하세요.ApplicationRegion
: Azure Cosmos DB와 상호 작용하기 위한 기본 지리적 복제 지역을 설정하려면 이 옵션을 사용합니다. 자세한 내용은 Azure Cosmos DB로 데이터를 전역적으로 배포를 참조하세요.ConsistencyLevel
: 이 옵션을 사용하면 기본 일관성 수준을 재정의할 수 있습니다. 자세한 내용은 Azure Cosmos DB의 일관성 수준을 참조하세요.BulkExecutionMode
:AllowBulkExecution
속성을true
로 설정하여 대량 작업을 실행하려면 이 옵션을 사용합니다. 자세한 내용은 .NET SDK를 사용하여 Azure Cosmos DB for NoSQL 계정으로 데이터를 대량으로 가져오기를 참조하세요.client_cosmosDB = new CosmosClient(" Your connection string ",new CosmosClientOptions() { ConnectionMode=ConnectionMode.Direct, ApplicationRegion=Regions.EastUS2, ConsistencyLevel=ConsistencyLevel.Session, AllowBulkExecution=true });
컨테이너 만들기
DynamoDB
Amazon DynamoDB에 데이터를 저장하려면 먼저 테이블을 만들어야 합니다. 다음 코드와 같이 스키마, 키 형식 및 특성을 정의합니다.
// 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 (애저 코스모스 DB)
Amazon DynamoDB에서는 읽기 컴퓨팅 단위와 쓰기 컴퓨팅 단위를 프로비전해야 합니다. Azure Cosmos DB에서는 처리량을 RU/s(초당 요청 단위)로 지정합니다. 모든 작업에 RU/s를 동적으로 사용할 수 있습니다. 데이터는 데이터베이스, 컨테이너, 항목 순으로 구성됩니다. 처리량은 데이터베이스 수준, 컬렉션 수준 또는 둘 다에서 지정할 수 있습니다.
데이터베이스를 만들려면
await client_cosmosDB.CreateDatabaseIfNotExistsAsync(movies_table_name);
컨테이너를 만들려면:
await cosmosDatabase.CreateContainerIfNotExistsAsync(new ContainerProperties() { PartitionKeyPath = "/" + partitionKey, Id = new_collection_name }, provisionedThroughput);
데이터 로드
DynamoDB
다음 코드에서는 Amazon DynamoDB에서 데이터를 로드하는 방법을 보여 줍니다. moviesArray
코드는 JSON 문서를 나열한 다음 JSON 문서를 반복하여 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 (애저 코스모스 DB)
Azure Cosmos DB에서는 moviesContainer.CreateItemStreamAsync()
를 사용하여 스트리밍하고 쓰기를 선택할 수 있습니다. 하지만 이 예에서는 JSON을 MovieModel
형식으로 역직렬화하여 형식 캐스팅 기능을 보여 줍니다. 이 코드는 멀티스레드 방식으로 동작하며 Azure Cosmos DB의 분산 아키텍처를 사용하여 로딩 속도를 높입니다.
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);
문서 만들기
DynamoDB
Amazon DynamoDB에서 새 문서를 작성하는 것은 형식이 안전하지 않습니다. 다음 예에서는 문서 형식으로 newItem
을 사용합니다.
Task<Document> writeNew = moviesTable.PutItemAsync(newItem, token);
await writeNew;
Azure Cosmos DB (애저 코스모스 DB)
Azure Cosmos DB는 데이터 모델을 통해 형식 안전성을 제공합니다. 이 예에서는 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);
}
}
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;
문서 읽기
DynamoDB
Amazon DynamoDB에서 읽으려면 기본 형식을 정의해야 합니다.
// 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 (애저 코스모스 DB)
Azure Cosmos DB를 사용하면 쿼리는 자연어 쿼리입니다(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;
}
이전 예의 문서 컬렉션은 형식이 안전하며 자연스러운 쿼리 옵션을 제공합니다.
항목 업데이트
DynamoDB
Amazon DynamoDB에서 항목을 업데이트하려면:
updateResponse = await client.UpdateItemAsync( updateRequest );
Azure Cosmos DB (애저 코스모스 DB)
Azure Cosmos DB에서 업데이트는 Upsert
작업으로 처리됩니다(즉, 문서가 없으면 삽입).
await moviesContainer.UpsertItemAsync<MovieModel>(updatedMovieModel);
문서 삭제
DynamoDB
Amazon DynamoDB에서 항목을 삭제하려면 기본 형식을 사용해야 합니다.
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 (애저 코스모스 DB)
Azure Cosmos DB에서는 문서를 가져와 비동기식으로 삭제할 수 있습니다.
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));
}
}
쿼리 문서
DynamoDB
Amazon DynamoDB에서 데이터를 쿼리하려면 API 함수가 필요합니다.
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 (애저 코스모스 DB)
Azure Cosmos DB에서는 간단한 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'))");
범위 작업(예: between
)의 경우 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( );
Azure Cosmos DB에서 SQL 쿼리와 한 줄로 된 문을 사용할 수 있습니다.
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");
컨테이너 삭제
DynamoDB
Amazon DynamoDB에서 테이블을 삭제하려면 다음을 지정할 수 있습니다.
client.DeleteTableAsync( tableName );
Azure Cosmos DB (애저 코스모스 DB)
Azure Cosmos DB에서 컬렉션을 삭제하려면 다음을 지정할 수 있습니다.
await moviesContainer.DeleteContainerAsync();
필요한 경우 데이터베이스도 삭제합니다.
await cosmosDatabase.DeleteAsync();
요약
이전 예에서 알 수 있듯이 Azure Cosmos DB는 자연스러운 쿼리(SQL)를 지원하며 작업은 비동기적으로 진행됩니다. 복잡한 코드를 Azure Cosmos DB로 쉽게 마이그레이션할 수 있습니다. 마이그레이션 후 코드가 더 단순해집니다.
관련 콘텐츠
- 성능 최적화에 대해 알아보기
- 읽기와 쓰기를 최적화하는 방법을 알아봅니다.
- Azure Cosmos DB의 모니터링에 대해 알아봅니다.