EF Core Azure Cosmos DB 공급자를 사용하여 데이터 저장

기본 사항 저장

Azure Cosmos DB 공급자를 사용하여 데이터를 저장하는 것은 다른 공급자와 비슷한 방식으로 작동합니다. 엔터티를 추가, 수정 또는 제거한 다음, 해당 변경 내용을 데이터베이스에 유지하도록 호출 SaveChangesAsync 합니다. 저장의 기본 사항에 대한 자세한 내용은 데이터 저장을 참조하세요.

트랜잭션성 및 트랜잭션 일괄 처리

비고

트랜잭션 일괄 처리 지원은 현재 미리 보기 상태인 EF Core 11에서 도입되고 있습니다.

Azure Cosmos DB는 원자성 트랜잭션에 대해 제한된 지원을 제공합니다. 이는 엄격한 트랜잭션 의미 체계가 아닌 확장성 및 가용성에 중점을 둔 문서 데이터베이스의 일반적인 제한 사항입니다. Azure Cosmos DB는 단일 파티션 내에서 작업을 일괄 처리로 함께 실행할 수 있도록 하는 트랜잭션 일괄 처리를 지원합니다(아래 추가 제한 사항 참조). 원자성은 단일 일괄 처리 내에서 보장됩니다. 작업이 실패하면 전체 일괄 처리가 롤백되고 변경 내용이 적용되지 않습니다. 그러나 일괄 처리가 작성되면 롤백하거나 지연할 수 없으며 원자성은 여러 일괄 처리에 적용할 수 없습니다. 또한 트랜잭션 일괄 처리는 각 업데이트에 대해 왕복을 수행하는 대신 여러 문서를 단일 왕복으로 업데이트할 수 있으므로 성능 이점을 제공합니다.

EF 11부터 EF Core Azure Cosmos DB 공급자는 가능한 경우 트랜잭션 일괄 처리를 기본 수행 방식으로 활용하여 변경 사항 저장 시 원자성을 최대한 근사치로 제공하며, 최적의 성능을 보장합니다. 일괄 처리 동작은 속성에 의해 AutoTransactionBehavior 제어될 수 있으므로 개발자는 애플리케이션의 요구 사항에 따라 성능, 일관성 보장 및 실패 동작 간에 절차할 수 있습니다.

  • 자동 (기본값) – EF는 순차적으로 실행되는 트랜잭션 일괄 처리로 작업을 자동으로 그룹화합니다. 일괄 처리가 실패하면 실행이 즉시 중지되고 후속 변경 내용이 저장되지 않지만 이전에 성공한 일괄 처리는 커밋된 상태로 유지됩니다. 일반적으로 파티션 키 값별로 그룹화할 수 있는 여러 작업을 수행할 때 원자성을 최대한 근사치로 사용하여 좋은 성능을 제공합니다.
  • Never – 모든 작업은 추적된 정확한 순서대로 개별적으로 순차적으로 수행됩니다. 이렇게 하면 일괄 처리가 방지되고 특히 많은 변경 내용의 경우 속도가 느려질 수 있습니다. 이는 버전 11 이전의 동작이었습니다.
  • Always – 모든 작업을 단일 트랜잭션 일괄 처리로 실행할 수 있어야 합니다. 일괄 처리에 작업을 포함할 수 없는 경우( 제한 사항 참조) 예외가 throw됩니다. 이렇게 하면 SaveChangesAsync를 실행할 때 전체 원자성(및 단일 왕복)을 보장할 수 있습니다. 그러나 각 작업이 트랜잭션 배치로 수행될 수 있도록 수동으로 확인하는 것은 사용자 책임입니다.

다음은 너무 많은 작업이 시도되어 실패하게 되는 Always 사용법의 예로, SaveChangesAsync을(를) 사용하는 경우입니다.

using var context = new BlogsContext();
context.Database.AutoTransactionBehavior = AutoTransactionBehavior.Always;
context.AddRange(Enumerable.Range(0, 101).Select(i => new Post())); // 101 entries exceeds the batch item limit of 100.
await context.SaveChangesAsync(); // Throws InvalidOperationException since the changes cannot be saved in a single batch.

제한점

  • 트랜잭션 일괄 처리는 단일 파티션 내에서만 수행할 수 있습니다.
  • 트랜잭션 일괄 처리는 최대 100개의 작업만 포함할 수 있으며 총 2MB의 데이터를 초과할 수 없습니다.
  • Azure Cosmos DB는 사전 또는 사후 트리거 가 있는 문서 쓰기를 트랜잭션 일괄 처리의 일부로 허용하지 않습니다. 이로 인해 트리거로 구성된 모든 엔터티는 트랜잭션 일괄 처리 전에 개별적으로 실행됩니다. 이는 혼합 시나리오의 순서 및 일관성에 영향을 줄 수 있습니다.

대량 실행

비고

대량 실행은 현재 미리 보기 상태인 EF Core 11에서 도입되고 있습니다.

버전 11 이전에는 Azure Cosmos DB 공급자가 호출 SaveChangesAsync할 때 순차적으로 문서 작업을 실행했습니다. 많은 수의 엔터티를 저장할 때 각 작업이 시작하기 전에 이전 작업이 완료될 때까지 대기하므로 속도가 느렸습니다. 버전 11을 사용하면 트랜잭션 일괄 처리를 사용할 수 있으므로 성능 향상을 위해 작업을 함께 일괄 처리할 수 있습니다. 그러나 트랜잭션 일괄 처리는 단일 파티션에 대해서만 사용할 수 있으며 다양한 제한 사항이 있습니다(위의 설명서 참조).

다른 방법은 Azure Cosmos DB를 사용하여 대량 실행을 지원하므로 여러 문서 작업을 DbContext 인스턴스 간에 병렬로 실행할 수 있으므로 많은 엔터티를 한 번에 저장할 때 처리량이 크게 향상됩니다. 이는 데이터 로드 시나리오, 일괄 처리 작업 또는 많은 엔터티를 저장해야 하는 상황에 특히 유용합니다.

대량 실행을 사용하도록 설정하려면 다음 옵션을 사용하여 컨텍스트를 BulkExecutionEnabled() 구성합니다.

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    => optionsBuilder.UseCosmos(
        "https://localhost:8081",
        "C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==",
        databaseName: "OrdersDB",
        options => options.BulkExecutionEnabled());

대량 실행을 사용하도록 설정하면 문서 쓰기 작업이 순차적으로 실행되지 않고 병렬로 실행됩니다. 특히 수백 또는 수천 개의 문서가 포함된 시나리오에서 여러 엔터티를 저장할 때 성능이 크게 향상될 수 있습니다. 그러나 이를 사용하도록 설정하기 전에 주의 사항을 이해해야 합니다. 동작은 SaveChangesAsync API 관점에서 동일하게 유지됩니다. Azure Cosmos DB의 대량 기능을 활용하기 위해 변경되는 것은 내부 실행일 뿐입니다.

Azure Cosmos DB의 대량 실행에 대한 자세한 내용은 다음 Azure 설명서를 참조하세요.

세션 토큰 관리

비고

세션 토큰 관리는 현재 미리 보기 상태인 EF Core 11에서 도입되고 있습니다.

Azure Cosmos DB 는 세션 토큰을 사용하여 세션 내에서 읽기-쓰기 일관성을 추적합니다. 세션 일관성(기본값)을 사용하는 경우 각 읽기 또는 쓰기 작업은 요청 클라이언트가 자체 쓰기를 읽도록 후속 요청에 사용할 수 있는 세션 토큰을 반환합니다.

기본적으로 Azure Cosmos DB .NET SDK는 단일 CosmosClient 인스턴스 내에서 세션 토큰을 자동으로 관리합니다. 그러나 일부 시나리오에서는 세션 토큰을 수동으로 관리해야 할 수 있습니다.

  • 애플리케이션이 HTTP 요청 간의 세션 연결성을 유지하지 않는 라운드 로빈 부하 분산기를 사용하는 경우
  • 애플리케이션을 다시 시작할 때 세션 토큰을 유지 및 복원해야 하는 경우
  • 세션 토큰을 서로 다른 DbContext 인스턴스 또는 애플리케이션 프로세스 간에 공유해야 하는 경우

세션 토큰 관리 모드 구성

수동 세션 토큰 관리를 사용하도록 설정하려면 컨텍스트를 설정할 때 SessionTokenManagementMode()을(를) 구성합니다.

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    => optionsBuilder.UseCosmos(
        "<connection string>",
        databaseName: "OrdersDB",
        options => options.SessionTokenManagementMode(SessionTokenManagementMode.SemiAutomatic));

다음 모드를 사용할 수 있습니다.

Mode Description
FullyAutomatic 기본 모드입니다. 기본 Cosmos DB SDK 자동 세션 토큰 관리를 사용합니다. GetSessionTokens 및 UseSessionTokens 메서드는 호출될 때 throw됩니다.
SemiAutomatic 를 통해 UseSessionTokensSDK의 자동 세션 토큰 관리를 덮어쓸 수 있습니다. 컨테이너에 대해 호출되지 않은 경우 UseSessionTokens SDK의 자동 관리가 사용됩니다. EF는 세션 토큰을 추적하고, GetSessionTokens을 통해 검색할 수 있습니다.
Manual SDK 자동 세션 토큰 관리를 완전히 대체합니다. EF 작업에 의해 추적되거나 UseSessionTokens를 통해 지정된 세션 토큰만 사용됩니다.
EnforcedManual Manual와 같지만, UseSessionTokens이 컨테이너에 대해 호출되지 않은 상태에서 컨테이너에 작업을 실행하려고 할 때 예외를 throw합니다.

세션 토큰 검색

읽기 또는 쓰기 작업을 수행한 후 EF에서 추적하는 세션 토큰을 검색할 수 있습니다.

// Get the session token for the default container
string? sessionToken = context.Database.GetSessionToken();

// Get session tokens for all containers
IReadOnlyDictionary<string, string?> allTokens = context.Database.GetSessionTokens();

세션 토큰 설정

읽기 작업을 수행하기 전에 세션 토큰을 설정하여 자신의 쓰기를 읽을 수 있습니다.

// Set the session token for the default container
context.Database.UseSessionToken(sessionToken);

// Set session tokens for all containers
context.Database.UseSessionTokens(sessionTokens);

세션 토큰 추가

세션 토큰을 기존 토큰에 추가할 수도 있습니다. 이는 여러 원본의 세션 토큰이 있고 이를 결합하려는 경우에 유용합니다.

// Append a session token for the default container
context.Database.AppendSessionToken(sessionToken);

// Append session tokens for the specified containers
context.Database.AppendSessionTokens(sessionTokens);

예: 부하 분산된 웹 애플리케이션의 세션 토큰 관리

다음 예제에서는 라운드 로빈 부하 분산 장치 뒤에 여러 인스턴스가 있는 웹 애플리케이션에서 세션 토큰을 관리하는 방법을 보여 줍니다.

// After writing data, retrieve and store the session token (e.g., in a cookie or header)
public async Task<IActionResult> CreateDocument(DocumentDto dto)
{
    await using var context = new MyCosmosContext();

    var document = new Document { Name = dto.Name };
    context.Documents.Add(document);
    await context.SaveChangesAsync();

    // Retrieve the session token to return to the client
    var sessionToken = context.Database.GetSessionToken();

    // Store in response header for the client to send back in subsequent requests
    Response.Headers["x-cosmos-session-token"] = sessionToken;

    return Ok(document.Id);
}

// Before reading data, apply the session token from the client
public async Task<IActionResult> GetDocument(int id)
{
    await using var context = new MyCosmosContext();

    // Get the session token from the request header
    if (Request.Headers.TryGetValue("x-cosmos-session-token", out var sessionToken))
    {
        context.Database.UseSessionToken(sessionToken!);
    }

    var document = await context.Documents.FindAsync(id);
    return document is not null ? Ok(document) : NotFound();
}

경고

수동 세션 토큰 관리는 제대로 처리되지 않을 때 세션 일관성을 깨뜨릴 수 있습니다. 세션 선호도 없이 부하 분산 장치 뒤에서 실행하는 것과 같이 특정한 필요성이 있는 경우에만 수동 모드를 사용합니다. 자세한 내용은 Azure Cosmos DB 설명서의 세션 토큰 활용을 참조하세요.