Azure Cosmos DB에서 성능 최적화: 최상의 실천 방법과 팁

데이터베이스 작업 시 최적화는 애플리케이션 성능과 효율성 측면에서 매우 중요합니다. 마찬가지로 Azure Cosmos DB에서도 최적화는 효율성을 극대화하고 비용을 최소화하며 애플리케이션이 효과적으로 확장되도록 보장하는 데 필수적입니다. 아래는 Azure Cosmos DB에서 성능을 최적화하기 위한 몇 가지 모범 사례와 코딩 예제입니다.

1. 올바른 파티션 키 선택

적절한 파티션 키를 선택하는 것은 Cosmos DB와 같은 분산 데이터베이스에 매우 중요합니다. 좋은 파티션 키는 데이터가 파티션 간에 고르게 분포되도록 하여 핫스팟을 줄이고 성능을 향상시킵니다.

파티션 키 선택은 간단하지만 Azure Cosmos DB 설계 시 매우 중요합니다.일단 우리가 파티션 키를 선택하면, 이를 제자리에서 변경하는 것은 불가능합니다.

모범 사례

  • 고유 값이 많은 높은 카디널리티를 가진 파티션 키를 선택하세요.
  • 읽기 및 쓰기가 고르게 분포되도록 하세요.
  • 관련 데이터를 함께 유지하여 교차 파티션 쿼리를 최소화하세요.

예제: 최적의 파티션 키로 컨테이너 생성

C#

 

var database = await cosmosClient.CreateDatabaseIfNotExistsAsync("YourDatabase");
var containerProperties = new ContainerProperties
{
    Id = "myContainer",
    PartitionKeyPath = "/customerId"  // Partition key selected to ensure balanced distribution
}; 

// 400 RU/s 프로비저닝된 처리량으로 컨테이너 생성
var container = await database.CreateContainerIfNotExistsAsync(containerProperties, throughput: 400);

2. 적절한색인사용

Azure Cosmos DB에서는 모든 속성에 대해 기본적으로 색인이 적용되며, 이는 유익할 수 있지만 저장 및 RU/s 비용이 증가할 수 있습니다. 쿼리 성능을 향상시키고 비용을 최소화하려면 색인 정책을 사용자 정의하는 것이 좋습니다. Cosmos DB는 범위 색인, 공간 색인 및 복합 색인 세 가지 유형의 색인을 지원합니다. 적절한 유형을 현명하게 사용하십시오.

최상의 실천 방법

  • 색인에서 불필요한 필드를 제외합니다.
  • 다중 필드 쿼리에 대해 복합 색인을 사용합니다.

예: 사용자 지정 색인 정책

C#

 

{
    "indexingPolicy": {
        "automatic": true,
        "indexingMode": "consistent",  // Can use 'none' or 'lazy' to reduce write costs
        "includedPaths": [
            {
                "path": "/orderDate/?",  // Only index specific fields like orderDate
                "indexes": [
                    {
                        "kind": "Range",
                        "dataType": "Number"
                    }
                ]
            }
        ],
        "excludedPaths": [
            {
                "path": "/largeDataField/*"  // Exclude large fields not used in queries
            }
        ]
    }
}

최적화된 쿼리를 위한 복합 색인 추가 예

C#

 

{
    "indexingPolicy": {
        "compositeIndexes": [
            [
                { "path": "/lastName", "order": "ascending" },
                { "path": "/firstName", "order": "ascending" }
            ]
        ]
    }
}

색인 유형에 대해 더 읽어보려면 여기를 확인하십시오.

3. 쿼리 최적화

Azure Cosmos DB에서 효율적인 쿼리는 요청 단위(RU/s)를 최소화하고 성능을 향상시키는 데 중요합니다. RU/s 비용은 쿼리의 복잡성과 크기에 따라 달라집니다.

대량 실행자를 활용하면 작업 당 소비되는 RU를 줄여 비용을 더욱 절감할 수 있습니다. 이 최적화를 통해 RU 사용량을 효과적으로 관리하고 전체 Cosmos DB 비용을 낮출 수 있습니다.

모범 사례

  • SELECT 쿼리를 사용하십시오 제한된 양으로, 필요한 속성만 검색하십시오.
  • 쿼리에서 파티션 키를 제공하여 교차 파티션 쿼리를 피하십시오.
  • 쿼리 비용을 줄이기 위해 인덱스 필드에 필터를 사용하십시오.

예: 고객 기록 가져오기

C#

 

var query = new QueryDefinition("SELECT c.firstName, c.lastName FROM Customers c WHERE c.customerId = @customerId")
    .WithParameter("@customerId", "12345");

var iterator = container.GetItemQueryIterator<Customer>(query, requestOptions: new QueryRequestOptions
{
    PartitionKey = new PartitionKey("12345")  // Provide partition key to avoid cross-partition query
});

while (iterator.HasMoreResults)
{
    var response = await iterator.ReadNextAsync();
    foreach (var customer in response)
    {
        Console.WriteLine($"{customer.firstName} {customer.lastName}");
    }
}

4. 일관성 수준 조정

일관성 수준은 속도 관련 보장을 충족하기 위해 설계된 특정 운영 모드를 정의합니다. 다섯 가지 일관성 수준(강력, 제한된 신선도, 세션, 일관된 접두사 및 최종)Cosmos DB에서 사용할 수 있습니다. 각 일관성 수준은 지연 시간, 가용성 및 처리량에 영향을 미칩니다.

모범 사례

  • 대부분의 시나리오에 대해 성능과 데이터 일관성을 균형 있게 유지하기 위해 세션 일관성을 사용하십시오.
  • 강력한 일관성 은 데이터 일관성을 보장하지만 RU/s 및 지연 시간을 증가시킵니다.

예: 일관성 수준 설정

C#

 

var cosmosClient = new CosmosClient(
    "",
    "",
    new CosmosClientOptions
    {
        // 균형 잡힌 성능을 위해 일관성을 "세션"으로 설정합니다
		ConsistencyLevel = ConsistencyLevel.Session      
});

일관성 수준에 대해 더 알아보세요 여기에서.

5. Provisioned Throughput (RU/s)와 Auto-Scale을 현명하게 사용하세요

처리량을 프로비저닝하는 것은 Azure Cosmos DB에서 비용 효율성과 최적 성능을 달성하는 데 중요한 요소입니다. 이 서비스는 처리량을 두 가지 방식으로 구성할 수 있습니다:

  • 고정 RU/s: 초당 요청 단위(Request Units) 수준이 미리 정의된 고정 수준으로, 일관된 성능 요구 사항을 갖는 워크로드에 적합합니다.
  • 자동 확장: 워크로드 변동에 따라 자동으로 처리량을 조정하는 동적 옵션으로, 확장성을 제공하면서 활동이 적은 기간에 과다하게 프로비저닝을 피합니다.

적절한 처리량 모델을 선택하여 성능 요구와 비용 관리를 효과적으로 조화시킵니다.

권장사항

  • 예측 가능한 워크로드의 경우 처리량을 수동으로 프로비저닝하세요.
  • 예측할 수 없거나 버스트 형태의 워크로드의 경우 자동 확장을 사용하세요.

예시: 자동 확장으로 처리량 프로비저닝예시: 안정적인 워크로드에 대한 고정 RU/s 수동 설정

C#

 

var throughputProperties = ThroughputProperties.CreateAutoscaleThroughput(maxThroughput: 4000);  // Autoscale up to 4000 RU/s 
var container = await database.CreateContainerIfNotExistsAsync(new ContainerProperties
{
	Id = "autoscaleContainer",
	PartitionKeyPath = "/userId"
}, throughputProperties);

  

C#

 

var container = await database.CreateContainerIfNotExistsAsync(new ContainerProperties
{
    Id = "manualThroughputContainer",
    PartitionKeyPath = "/departmentId"
}, throughput: 1000);  // Fixed 1000 RU/s

6. 효율적인 실시간 처리를 위한 변경 피드 활용

변경 피드는 데이터베이스의 변화를 자동으로 캡처하여 실시간 이벤트 기반 처리를 가능하게 하며, 폴링의 필요성을 없애줍니다. 이는 쿼리 오버헤드를 줄이고 효율성을 향상시킵니다.

모범 사례

  • 실시간 데이터 변경 사항을 처리해야 하는 시나리오(예: 실시간 분석, 알림, 경고 등)에 변경 피드를 사용하세요.

예: 변경 피드에서 읽기

C#

 

var iterator = container.GetChangeFeedIterator(
ChangeFeedStartFrom.Beginning(),
ChangeFeedMode.Incremental);
while (iterator.HasMoreResults)
{
    var changes = await iterator.ReadNextAsync();
    foreach (var change in changes)
    {
        Console.WriteLine($"Detected change: {change.Id}");
        // 변경 사항 처리(예: 이벤트 트리거, 캐시 업데이트)
    }
}

7. 자동 데이터 만료를 위한 TTL(Time-to-Live) 활용

로그나 세션 데이터와 같이 한정된 시간 동안만 관련 있는 데이터가 있다면, Azure Cosmos DB에서 TTL(Time-to-Live)을 활성화하여 저장 비용을 관리할 수 있습니다. TTL은 지정된 보존 기간 이후 만료된 데이터를 자동으로 삭제하여 수동 데이터 정리의 필요성을 없앱니다. 이 접근 방식은 저장된 데이터의 양을 줄일 뿐만 아니라, 구식이거나 불필요한 정보를 제거하여 데이터베이스의 비용 효율성을 최적화합니다.

모범 사례

  • 저장 비용을 줄이기 위해 데이터가 자동으로 만료되어야 하는 컨테이너에 TTL을 설정하세요.

예: 만료되는 데이터에 대한 TTL 설정

C#

 

{
    "id": "sessionDataContainer",
    "partitionKey": { "paths": ["/sessionId"] },
    "defaultTtl": 3600  // 1 hour (3600 seconds)
}

코스모스 DB에서, 설정할 수 있는 최대 생존 시간(TTL) 값은 365일(1년)입니다. 이는 TTL을 구성하는 방식에 따라 데이터가 생성 또는 마지막 수정 후 1년 이내에 만료되면 자동으로 삭제될 수 있음을 의미합니다.

8. 교차 파티션 쿼리 피하기

교차 파티션 쿼리는 RU/s와 지연 시간을 크게 증가시킬 수 있습니다. 이를 피하려면:

모범 사례

  • 항상 쿼리에 파티션 키를 포함하세요.
  • 교차 파티션 접근을 최소화하도록 파티션 전략을 설계하세요.

예: 교차 파티션 쿼리를 피하기 위한 파티션 키로 쿼리하기

C#

 

var query = new QueryDefinition("SELECT * FROM Orders o WHERE o.customerId = @customerId")
    .WithParameter("@customerId", "12345"); 

var resultSetIterator = container.GetItemQueryIterator<Order>(query, requestOptions: new QueryRequestOptions
{
    PartitionKey = new PartitionKey("12345")
});

while (resultSetIterator.HasMoreResults)
{
    var response = await resultSetIterator.ReadNextAsync();
    foreach (var order in response)
    {
        Console.WriteLine($"Order ID: {order.Id}");
    }
}

결론

이 팁은 개발 중 매우 효과적입니다. 효과적인 파티셔닝 전략을 구현하고, 인덱싱 정책을 사용자 정의하고, 쿼리를 최적화하고, 일관성 수준을 조정하며, 적절한 처리량 프로비저닝 모델을 선택함으로써 Azure Cosmos DB 배포의 성능과 효율성을 크게 향상시킬 수 있습니다. 이러한 최적화는 확장성을 높일 뿐만 아니라 비용 관리에도 도움을 주면서 고성능 데이터베이스 경험을 제공합니다.

Source:
https://dzone.com/articles/optimizing-performance-in-azure-cosmos-db