13년차의 서버실

서버, 인프라, 홈랩 기술 블로그

[태그:] Azure Cosmos DB

  • [Cloud] Cosmos DB 마이그레이션 가이드: 기존 DB에서 NoSQL로 안전하게 전환하기

    [Cloud] Cosmos DB 마이그레이션 가이드: 기존 DB에서 NoSQL로 안전하게 전환하기

    안녕하세요, 13년차 인프라 엔지니어입니다. 오늘은 저처럼 관계형 데이터베이스(Relational Database) 환경에 익숙한 분들이 NoSQL로 전환할 때 겪는 Cosmos DB 마이그레이션 경험담을 풀어볼까 합니다. 특히 기존 DB에서 NoSQL로 넘어갈 때 마주치는 문제들과 제가 삽질 끝에 찾아낸 해결 방안들을 여과 없이 공유하려고 해요.

    최근 서비스가 빠르게 성장하면서 기존 RDB로는 감당하기 어려운 트래픽과 데이터 규모에 직면하는 경우가 많아졌습니다. 저도 직접 운영하는 서비스에서 비슷한 고민을 했거든요. 이럴 때 확장성과 유연성이 뛰어난 NoSQL 데이터베이스, 특히 Azure Cosmos DB 같은 글로벌 분산 데이터베이스가 매력적인 대안으로 떠오릅니다. 하지만 익숙한 환경을 떠나 새로운 패러다임으로 넘어가는 건 결코 쉽지 않죠. 😅

    기존 관계형 데이터베이스에서 Azure Cosmos DB로 마이그레이션하는 전체 아키텍처 개요도

    Cosmos DB와 NoSQL 마이그레이션, 왜 필요한가?

    Cosmos DB는 Microsoft Azure에서 제공하는 완전 관리형(fully managed) NoSQL 데이터베이스 서비스입니다. 전 세계 어디서든 낮은 지연 시간(low-latency)으로 데이터를 읽고 쓸 수 있으며, 필요에 따라 자동으로 확장(auto-scale)되는 것이 가장 큰 장점이죠. 특히 여러 NoSQL API를 지원해서(SQL API, MongoDB API, Cassandra API, Gremlin API 등) 기존에 사용하던 NoSQL 시스템과 호환성을 유지하면서 Cosmos DB 마이그레이션을 진행할 수 있다는 점이 매력적입니다.

    그렇다면 왜 굳이 NoSQL 마이그레이션을 해야 할까요? 제가 직접 경험해보니 몇 가지 확실한 이유가 있더라고요.

    • 확장성 (Scalability): 폭발적으로 증가하는 데이터와 트래픽을 RDB의 수직 확장(vertical scaling)만으로는 감당하기 어렵습니다. NoSQL은 수평 확장(horizontal scaling)에 유리하죠.
    • 유연한 스키마 (Flexible Schema): RDB는 엄격한 스키마를 요구해서 데이터 모델 변경 시 복잡한 마이그레이션 작업이 필요합니다. NoSQL은 스키마가 유연해서 빠르게 변화하는 비즈니스 요구사항에 대응하기 좋습니다.
    • 글로벌 분산 (Global Distribution): 전 세계 사용자에게 서비스를 제공해야 할 때, Cosmos DB는 몇 번의 클릭만으로 전 세계 리전에 데이터를 복제하고 동기화할 수 있습니다.

    이런 장점들 때문에 데이터베이스 전환을 고민하게 되지만, 막상 시작하면 만만치 않은 벽에 부딪힙니다. 가장 큰 벽은 바로 데이터 모델링과 마이그레이션 전략 수립이더군요.

    마이그레이션 준비: 데이터 모델링이 반이다

    관계형 데이터베이스는 정규화(Normalization)를 통해 데이터 중복을 최소화하고 데이터 무결성을 유지합니다. 하지만 NoSQL은 읽기 성능(read performance)을 최적화하기 위해 비정규화(Denormalization)를 적극적으로 활용하는 경우가 많습니다. 이게 처음엔 정말 낯설더라고요.

    Cosmos DB에서는 파티션 키 (Partition Key) 선정이 정말 중요합니다. 파티션 키는 데이터를 논리적 파티션으로 나누는 기준이 되는데, 이 키를 어떻게 정하느냐에 따라 성능과 비용이 천차만별로 달라지거든요. 잘못 정하면 ‘핫 파티션(Hot Partition)’이 생겨서 특정 파티션에만 부하가 몰려 성능 저하를 겪게 됩니다. 제가 이 부분에서 정말 크게 삽질했어요. ㅎㅎ

    💡 팁: 파티션 키는 카디널리티(Cardinality, 고유한 값의 수)가 높고, 읽기/쓰기 작업이 고르게 분산될 수 있는 필드를 선택하는 것이 좋습니다. 예를 들어, 사용자 ID나 주문 ID 같은 필드가 좋은 후보가 될 수 있죠.

    실전 마이그레이션: 데이터 이동 전략

    이제 실제로 데이터를 옮겨볼 차례입니다. Cosmos DB로 데이터를 마이그레이션하는 방법은 여러 가지가 있습니다.

    1. Azure Cosmos DB Data Migration Tool: GUI 기반의 도구로, CSV, JSON 파일, MongoDB, SQL Server 등 다양한 소스에서 데이터를 가져올 수 있습니다. 간단한 초기 마이그레이션에 유용합니다.
    2. Azure Data Factory (ADF): 대규모 데이터 마이그레이션, ETL(Extract, Transform, Load) 파이프라인 구축에 적합합니다. 다양한 데이터 소스와 싱크를 지원하며, 데이터 변환 로직을 추가할 수 있습니다.
    3. 커스텀 스크립트: Python, .NET 등 SDK를 이용해 직접 스크립트를 작성하여 데이터를 마이그레이션하는 방식입니다. 복잡한 변환 로직이나 실시간 동기화가 필요할 때 유용하죠.

    저는 초기 마이그레이션에는 Data Migration Tool을 사용했지만, 복잡한 데이터 변환이 필요해서 결국 Python 스크립트를 직접 작성했습니다. 기존 관계형 DB에서 데이터를 읽어와 NoSQL 모델에 맞게 변환한 뒤 Cosmos DB에 삽입하는 방식이었거든요.

    먼저 Azure CLI를 이용해 Cosmos DB 계정과 데이터베이스, 컨테이너를 생성하는 기본적인 명령어부터 살펴보겠습니다.

    # Azure 리소스 그룹 생성 (이미 있다면 생략)
    az group create --name myCosmosResourceGroup --location koreacentral
    
    # Cosmos DB 계정 생성 (API 종류는 필요에 따라 선택, 여기서는 SQL API)
    az cosmosdb create \
      --name mycosmosdbaccount13year \
      --resource-group myCosmosResourceGroup \
      --default-consistency-level Session \
      --locations regionName=koreacentral failoverPriority=0 \
      --kind GlobalDocumentDB
    
    # 데이터베이스 생성
    az cosmosdb sql database create \
      --account-name mycosmosdbaccount13year \
      --name myNoSQLDatabase \
      --resource-group myCosmosResourceGroup
    
    # 컨테이너 생성 (파티션 키는 /userId 로 예시)
    az cosmosdb sql container create \
      --account-name mycosmosdbaccount13year \
      --database-name myNoSQLDatabase \
      --name myItemsContainer \
      --partition-key-path /userId \
      --throughput 400 \
      --resource-group myCosmosResourceGroup
    

    그리고 Python으로 데이터를 읽어와 삽입하는 예시 코드입니다. 실제 환경에서는 데이터 변환 로직이 훨씬 복잡하겠죠.

    import os
    import json
    from azure.cosmos import CosmosClient
    
    # Cosmos DB 설정
    COSMOS_DB_ENDPOINT = os.environ.get("COSMOS_DB_ENDPOINT")
    COSMOS_DB_KEY = os.environ.get("COSMOS_DB_KEY")
    DATABASE_NAME = "myNoSQLDatabase"
    CONTAINER_NAME = "myItemsContainer"
    
    # Cosmos DB 클라이언트 초기화
    client = CosmosClient(COSMOS_DB_ENDPOINT, COSMOS_DB_KEY)
    database = client.get_database_client(DATABASE_NAME)
    container = database.get_container_client(CONTAINER_NAME)
    
    def migrate_data(data_list):
        print(f"Migrating {len(data_list)} items...")
        for item in data_list:
            try:
                # 기존 RDB 데이터를 NoSQL 모델에 맞게 변환 (예시)
                # item_transformed = {"id": str(item["old_id"]), "userId": item["user_id"], "productName": item["name"], ...}
                # 실제 데이터 변환 로직은 여기에 구현
                item_transformed = item # 단순 복사 (예시)
                item_transformed["id"] = str(item_transformed["id"]) # Cosmos DB item id는 문자열이어야 함
    
                container.upsert_item(body=item_transformed)
                # print(f"Inserted/Updated item: {item_transformed['id']}")
            except Exception as e:
                print(f"Error processing item {item.get('id', 'N/A')}: {e}")
    
    if __name__ == "__main__":
        # 예시 데이터 (실제로는 RDB에서 조회)
        sample_data = [
            {"id": 1, "userId": "userA", "productName": "Laptop", "price": 1200},
            {"id": 2, "userId": "userB", "productName": "Mouse", "price": 50},
            {"id": 3, "userId": "userA", "productName": "Keyboard", "price": 100},
            {"id": 4, "userId": "userC", "productName": "Monitor", "price": 300},
        ]
        migrate_data(sample_data)
        print("Migration complete!")
    
    Python 스크립트를 활용한 데이터 마이그레이션 과정 개념도

    Python 스크립트를 활용한 데이터 마이그레이션 과정 개념도

    삽질 경험: 파티션 키 잘못 설계했다가 고생했던 이야기 ⚠️

    제가 가장 크게 삽질했던 부분이 바로 파티션 키 (Partition Key) 설계였습니다. 처음에는 무심코 productId를 파티션 키로 잡았거든요. 저희 서비스는 특정 인기 상품에 대한 조회수가 압도적으로 높았는데, 아니나 다를까 얼마 지나지 않아 productId가 높은 특정 파티션에만 요청이 몰려서 Latency(지연 시간)가 급증하고 Request Unit(RU) 소모가 비정상적으로 치솟는 문제가 발생했습니다. 이게 바로 핫 파티션 (Hot Partition) 문제였죠. 😱

    Cosmos DB는 RU라는 개념으로 처리량을 측정하고 비용을 부과하는데, 핫 파티션이 발생하면 특정 파티션의 RU가 한계치에 도달하여 요청이 제한(throttling)될 수 있습니다. 전체 컨테이너의 RU가 여유 있어도 특정 파티션만 과부하가 걸리는 상황이 발생하더라고요. 이때 정말 당황했었습니다.

    해결책은 파티션 키를 userId와 같이 고르게 분산될 수 있는 값으로 변경하는 것이었습니다. 기존 데이터를 다시 마이그레이션해야 하는 대규모 작업이었지만, 장기적인 안정성을 위해서는 필수적인 선택이었죠. 이 경험을 통해 파티션 키 설계가 얼마나 중요한지 뼈저리게 느꼈습니다.

    RU (Request Unit)는 Cosmos DB에서 모든 데이터베이스 작업(읽기, 쓰기, 쿼리 등)에 대한 성능 단위입니다. 1 RU는 1KB 크기의 항목을 읽는 비용과 같습니다. 복잡한 쿼리나 큰 항목을 쓰면 더 많은 RU가 소모되죠. RU 사용량을 모니터링하면서 핫 파티션이 있는지 주기적으로 확인하는 것이 중요합니다.

    마이그레이션 후 검증 및 최적화

    데이터 마이그레이션이 끝났다고 끝이 아닙니다. 오히려 이때부터가 진짜 시작이죠! 마이그레이션 후에는 반드시 다음 사항들을 꼼꼼하게 검증하고 최적화해야 합니다.

    1. 데이터 일관성 (Data Consistency): 원본 데이터와 Cosmos DB의 데이터가 일치하는지 확인해야 합니다. 간단한 스크립트를 통해 레코드 수, 일부 필드의 합계 등을 비교하는 방법이 효과적입니다.
    2. 성능 벤치마킹 (Performance Benchmarking): 예상했던 성능이 나오는지 부하 테스트를 진행해야 합니다. 특히 핵심 비즈니스 로직에 대한 읽기/쓰기 Latency와 RU 소모량을 면밀히 관찰해야 합니다.
    3. 비용 모니터링 (Cost Monitoring): Cosmos DB는 사용량 기반 과금(pay-as-you-go)이므로, 예상치 못한 RU 소모로 비용 폭탄을 맞지 않도록 모니터링 대시보드를 설정하는 것이 중요합니다. Azure Portal에서 RU 사용량을 실시간으로 확인할 수 있습니다.

    Azure Portal에서 Cosmos DB 계정의 ‘메트릭 (Metrics)’ 섹션을 보면 RU 사용량, 지연 시간, 요청 수 등을 그래프로 볼 수 있습니다. 여기서 특정 파티션 키에 대한 요청이 급증하는 패턴이 보인다면 핫 파티션을 의심해봐야 합니다.

    Azure Portal의 Cosmos DB RU 사용량 및 성능 메트릭 대시보드 예시

    Azure Portal의 Cosmos DB RU 사용량 및 성능 메트릭 대시보드 예시

    Cosmos DB 마이그레이션 전략 선택 가이드

    다양한 상황에 따라 마이그레이션 전략도 달라질 수 있습니다. 제가 경험했던 것들을 바탕으로 몇 가지 시나리오별 추천 전략을 정리해봤습니다.

    시나리오 고려 사항 추천 마이그레이션 전략 주의사항
    소규모 초기 마이그레이션
    (데이터 양 < 100GB)
    빠른 전환, 데이터 모델 단순 Azure Cosmos DB Data Migration Tool 대규모 데이터에는 부적합, 복잡한 변환 어려움
    대규모 데이터 마이그레이션
    (데이터 양 > 100GB, 복잡한 ETL 필요)
    데이터 변환, 증분 동기화 Azure Data Factory (ADF) 활용 ADF 파이프라인 설계 및 운영 복잡성 증가
    실시간/Near Real-time 동기화
    (서비스 중단 최소화)
    무중단 전환, 이중 쓰기(Dual-write) 전략 커스텀 스크립트 + Change Feed 활용 이중 쓰기 로직 구현 및 동기화 일관성 관리 복잡
    기존 NoSQL (예: MongoDB) 에서 전환 API 호환성, 스키마 유사성 MongoDB API for Cosmos DB + Mongo Shell 또는 Data Migration Tool 일부 기능/성능 차이 고려
    Cosmos DB 마이그레이션 전략 선택 가이드 인포그래픽

    Cosmos DB 마이그레이션 전략 선택 가이드 인포그래픽

    마무리: 새로운 패러다임으로의 전환

    Cosmos DB 마이그레이션은 단순한 데이터 이동을 넘어, 데이터베이스 패러다임을 전환하는 일입니다. 제가 직접 겪어보니, 기존 관계형 DB의 사고방식에서 벗어나 NoSQL의 특성과 장점을 이해하는 것이 가장 중요하더라고요. 특히 파티션 키 설계나 RU 최적화 같은 부분은 충분한 학습과 테스트 없이는 큰 시행착오를 겪을 수밖에 없습니다.

    하지만 제대로만 설계하고 구현한다면, Cosmos DB는 여러분의 서비스에 강력한 확장성과 유연성을 제공할 것입니다. 이 글이 기존 DB에서 NoSQL로의 전환을 고민하는 분들께 작은 도움이 되었으면 좋겠네요. 다음에 기회가 된다면 Cosmos DB의 Change Feed를 활용한 실시간 데이터 처리 아키텍처에 대해서도 한번 다뤄보겠습니다. 궁금한 점이 있다면 언제든 댓글로 남겨주세요! 😊

  • [Azure] Azure Cosmos DB 일관성 모델 심층 분석: 데이터 무결성과 성능 최적화 전략

    [Azure] Azure Cosmos DB 일관성 모델 심층 분석: 데이터 무결성과 성능 최적화 전략

    목차

    [Azure] Azure Cosmos DB 일관성 모델 심층 분석

    Azure Cosmos DB 일관성 모델은 글로벌 분산 데이터 환경에서 성능과 데이터 무결성 사이의 균형을 잡을 때 가장 먼저 부딪히는 주제입니다. 분산 데이터베이스를 조금이라도 만져보신 분들은 아시겠지만, 쓰기(write) 직후 읽기(read) 결과가 항상 기대와 같지는 않거든요. 저도 처음에 NoSQL 시스템을 운영할 때는 “분산은 빠르면 된 거 아닌가?” 싶었는데, 실제로 써보니까 데이터 일관성 하나 때문에 장애 대응 방식이 완전히 달라지더라고요. 특히 Azure Cosmos DB 활용을 진지하게 고민하시는 분들이라면, 단순히 기본값만 쓰기보다 각 일관성 수준이 어떤 의미인지 이해하고 들어가셔야 삽질을 줄일 수 있습니다.

    이 글에서는 Azure Cosmos DB 일관성 모델의 핵심 개념을 쉽게 풀고, 실제 설정 흐름과 주의사항까지 같이 보겠습니다. 제가 직접 테스트 환경에서 만져보면서 헷갈렸던 포인트도 솔직하게 적어둘게요. 혹시 멀티 리전(multi-region) 환경에서 읽기 지연과 데이터 최신성 사이에서 고민하고 계셨다면, 여기서 감이 꽤 잡히실 겁니다.

    Azure Cosmos DB의 글로벌 분산 구조와 일관성 수준이 어디에서 영향을 주는지 보여주는 개요 이미지입니다.

    1. 왜 Azure Cosmos DB 일관성 모델이 중요한가

    쉽게 말해, 일관성(consistency)은 “방금 저장한 데이터가 언제, 어디서, 어떤 형태로 읽히느냐”에 대한 약속입니다. 전통적인 단일 데이터베이스에서는 이 약속이 비교적 단순했는데, 글로벌 분산 데이터 구조에서는 이야기가 달라집니다. 리전(region)이 여러 개면 네트워크 지연(latency), 복제(replication), 장애 조치(failover)가 모두 개입하거든요.

    Azure Cosmos DB는 이걸 아주 명확하게 모델로 제공합니다. 강한 일관성(Strong consistency)부터 최종 일관성(Eventual consistency)까지 다섯 가지 수준을 제공하고, 애플리케이션 특성에 맞게 선택하게 해줍니다. 이게 좋은 점도 있지만, 반대로 아무 생각 없이 고르면 성능이 아쉽거나 데이터 무결성 기대가 깨질 수 있습니다.

    • 금융성 트랜잭션처럼 최신 데이터가 중요하면 더 강한 일관성이 필요합니다.
    • 피드, 로그, 추천처럼 약간의 지연을 허용하면 더 느슨한 일관성으로 처리량(throughput)을 확보할 수 있습니다.
    • 글로벌 분산 데이터 환경에서는 리전별 읽기 경험이 달라질 수 있으니 더 신중해야 합니다.

    2. Azure Cosmos DB 일관성 모델 5가지, 쉽게 이해해보기

    Azure Cosmos DB 일관성 모델은 Strong, Bounded Staleness, Session, Consistent Prefix, Eventual 이렇게 다섯 가지입니다. 이름만 보면 딱딱한데, 실제 운영 관점으로 바꾸면 훨씬 이해가 쉽습니다.

    2-1. Strong consistency(강한 일관성)

    가장 직관적입니다. 쓰기가 완료되면 이후 읽기는 항상 최신 값을 봅니다. 관계형 데이터베이스의 익숙한 감각에 가장 가깝죠. 대신 지연 시간이 늘 수 있고, 글로벌 분산 시 선택에 제약이 생길 수 있습니다. 제가 처음엔 “무조건 Strong이 최고 아닌가?” 싶었는데, 멀티 리전 읽기를 붙여보면 비용과 응답성 관점에서 생각보다 부담이 있더라고요.

    2-2. Bounded Staleness(제한된 최신성 지연)

    최신 상태와의 차이를 어느 범위 안으로 제한하는 모델입니다. 예를 들어, 최대 몇 버전(prefix) 또는 몇 초(interval) 뒤처지는 것은 허용하되 무한정 늦어지지는 않게 보장하는 방식이죠. 강한 일관성보다 유연하면서도, “얼마나 늦을 수 있는지” 기준이 있다는 점이 운영에서 꽤 유용합니다.

    2-3. Session consistency(세션 일관성)

    실무에서 가장 현실적인 기본값으로 많이 거론되는 이유가 있습니다. 같은 클라이언트 세션(session) 안에서는 내가 쓴 데이터를 내가 바로 읽을 수 있는 read-your-writes 특성이 보장됩니다. 사용자별 작업 흐름이 중요한 애플리케이션에서는 이게 정말 편합니다. 실제로 써보니까 사용자 입장에서는 꽤 자연스럽고, 시스템 전체 비용도 과하게 키우지 않아서 균형이 좋더라고요.

    2-4. Consistent Prefix(일관된 접두사)

    데이터 순서는 꼬이지 않게 읽히지만, 최신 데이터가 아닐 수 있습니다. 예를 들어 A, B, C 순서로 쓴 이벤트가 있으면 B 없이 C만 먼저 보지는 않게 해줍니다. 이벤트 스트림(event stream)이나 로그성 데이터에서 순서 보장이 중요한 경우 이해해둘 만합니다.

    2-5. Eventual consistency(최종 일관성)

    가장 느슨합니다. 시간이 지나면 결국 동일해지지만, 당장은 서로 다른 리전이나 복제본에서 다른 값을 읽을 수 있습니다. 대신 지연과 확장성 측면에서는 가장 유리한 경우가 많습니다. 캐시성 조회나 약간 늦어도 되는 통계성 화면에서 자주 고려합니다.

    모델 최신성 순서 보장 대표 사용 사례
    Strong 매우 높음 보장 중요 트랜잭션, 즉시 반영 조회
    Bounded Staleness 높음 보장 지연 허용 범위를 제어해야 하는 서비스
    Session 세션 기준 높음 세션 기준 안정적 사용자 중심 웹/모바일 서비스
    Consistent Prefix 중간 보장 이벤트, 로그, 순서가 중요한 읽기
    Eventual 낮음 비보장 피드, 통계, 캐시성 데이터

    3. 분산 데이터베이스와 NoSQL에서 일관성 선택 기준

    여기서 중요한 포인트! Azure Cosmos DB 일관성 모델은 좋고 나쁨의 문제가 아니라, 업무 요구사항과의 적합성 문제입니다. 처음엔 다들 Strong에 끌립니다. 저도 그랬고요. 근데 운영을 해보면 사용자 행동 흐름, 리전 배치, 읽기 비율, 장애 시 복구 전략에 따라 정답이 달라집니다.

    • 사용자 본인이 방금 쓴 글을 바로 봐야 한다면 Session이 잘 맞습니다.
    • 결제 상태처럼 틀리면 안 되는 정보는 더 강한 일관성을 검토해야 합니다.
    • 전 세계 여러 리전에서 빠른 읽기가 핵심이면 느슨한 모델이 더 현실적일 수 있습니다.
    • 이벤트 발생 순서가 중요하면 Consistent Prefix를 고려할 수 있습니다.

    저는 보통 아래 질문으로 정리합니다.

    1. 사용자가 본인 작업 결과를 즉시 봐야 하나요?
    2. 오래된 데이터를 잠깐 보여줘도 되나요?
    3. 순서가 바뀌면 비즈니스 오류가 나나요?
    4. 멀티 리전 읽기 성능이 핵심인가요?
    5. 장애 조치 시에도 동일한 일관성 기대가 필요한가요?

    4. 실전 구현: Azure Cosmos DB 일관성 모델 설정하기

    이제 실전으로 가보겠습니다. 저는 테스트할 때 포털(Portal)에서도 확인하고, CLI로도 같이 만져보는 편입니다. 화면에서 설정해도 되지만, 운영 재현성과 변경 이력 관리를 생각하면 명령형 접근이 훨씬 낫더라고요.

    4-1. 계정 생성 시 기본 일관성 설정

    아래 예시는 Azure CLI로 Cosmos DB 계정을 만들면서 기본 일관성을 Session으로 지정하는 흐름입니다.

    RESOURCE_GROUP="rg-cosmos-demo"
    ACCOUNT_NAME="cosmos-demo-kr"
    LOCATION="koreacentral"
    
    az group create \
      --name "$RESOURCE_GROUP" \
      --location "$LOCATION"
    
    az cosmosdb create \
      --name "$ACCOUNT_NAME" \
      --resource-group "$RESOURCE_GROUP" \
      --locations regionName="$LOCATION" failoverPriority=0 \
      --default-consistency-level Session

    이렇게 생성해두면 기본 읽기 동작이 Session consistency(세션 일관성)를 기준으로 맞춰집니다. 사용자 중심 서비스라면 꽤 무난한 출발점입니다.

    4-2. Bounded Staleness로 변경하기

    업무 요구사항상 최신성 지연 범위를 명시적으로 통제해야 한다면 Bounded Staleness를 검토할 수 있습니다.

    az cosmosdb update \
      --name "$ACCOUNT_NAME" \
      --resource-group "$RESOURCE_GROUP" \
      --default-consistency-level BoundedStaleness \
      --max-interval-in-seconds 5 \
      --max-staleness-prefix 100

    여기서 max-interval-in-seconds와 max-staleness-prefix는 허용 가능한 지연 범위를 나타냅니다. 다만 이 값은 숫자만 보고 정할 게 아니라, 트래픽 패턴과 데이터 변경량을 같이 봐야 합니다. 저도 처음엔 감으로 넣었다가, 애플리케이션 기대 동작과 안 맞아서 다시 조정했었네요.

    Azure Cosmos DB 일관성 모델 설정 화면과 CLI 구성 이미지

    Cosmos DB 계정 생성 또는 업데이트 시 일관성 수준을 선택하는 흐름을 보여주는 이미지입니다.

    4-3. 애플리케이션 코드에서 읽기 일관성 이해하기

    애플리케이션에서는 계정의 기본 일관성 영향을 받습니다. 특히 Session consistency를 쓸 때는 같은 사용자의 연속 동작이 자연스럽게 이어지는지가 중요합니다. 예를 들어 문서를 저장하고 바로 조회하는 흐름을 테스트해보면 감이 확 옵니다.

    from azure.cosmos import CosmosClient, PartitionKey
    
    endpoint = "https://your-account.documents.azure.com:443/"
    key = "YOUR_KEY"
    database_name = "appdb"
    container_name = "orders"
    
    client = CosmosClient(endpoint, credential=key)
    database = client.get_database_client(database_name)
    container = database.get_container_client(container_name)
    
    item = {
        "id": "order-1001",
        "customerId": "user-1",
        "status": "created"
    }
    
    container.upsert_item(item)
    result = container.read_item(item="order-1001", partition_key="user-1")
    print(result)

    이 코드는 아주 단순하지만, 실제 테스트에서 중요한 건 “쓰기 직후 읽기 결과가 애플리케이션 기대와 맞는가”입니다. 같은 코드라도 일관성 수준에 따라 체감이 꽤 달라집니다.

    4-4. 검증용 질의 패턴 만들기

    테스트할 때는 한 번 읽고 끝내지 말고, 반복 조회 패턴을 만들어보시는 게 좋습니다. 특히 글로벌 분산 데이터 시나리오에서는 리전별로 관찰값이 다를 수 있으니까요.

    for i in {1..5}; do
      date
      curl -s "https://your-api.example.com/orders/order-1001"
      echo
      sleep 1
    done

    이런 식으로 애플리케이션 API를 통해 연속 읽기를 보면, 최신성 반영 시점이나 캐시 영향도 함께 파악할 수 있습니다.

    5. ⚠️ 제가 겪었던 주의사항과 트러블슈팅

    여기서부터가 진짜 운영 감각이 필요한 부분입니다. 문서만 읽으면 금방 이해한 것 같거든요. 근데 실제로 붙여보면, “왜 방금 쓴 값이 안 보이지?” 같은 순간이 꼭 옵니다. 저도 삽질 좀 했습니다 ㅎㅎ

    5-1. Session을 쓰는데도 최신값이 안 보이는 느낌

    이건 종종 애플리케이션 구조 문제일 수 있습니다. Session consistency는 같은 세션 흐름에서 read-your-writes가 핵심인데, 요청이 프록시(proxy)나 중간 계층을 거치면서 세션 문맥이 기대와 다르게 흘러갈 수 있거든요. 특히 여러 인스턴스 간 상태 공유를 잘못 이해하면 “세션이면 무조건 최신”이라고 착각하기 쉽습니다.

    해결 포인트는 간단합니다.

    • 같은 사용자 요청 흐름이 실제로 어떻게 라우팅되는지 확인합니다.
    • 애플리케이션 캐시가 결과를 가로채고 있지 않은지 봅니다.
    • 데이터베이스 일관성 문제와 API 계층 캐시 문제를 분리해서 테스트합니다.

    5-2. Strong이 무조건 안전하다고 생각했던 실수

    Strong consistency(강한 일관성)는 분명 강력합니다. 하지만 시스템 전체 요구가 그것을 정말 필요로 하는지 먼저 따져야 합니다. 읽기 응답성이 중요한 서비스에서 무조건 강한 일관성을 고르면 체감 성능과 아키텍처 유연성이 줄 수 있습니다. 저도 초반에는 안전하게 가자는 마음으로 더 강한 옵션만 보다가, 실제 요구사항을 다시 분석하고 Session으로 내린 적이 있습니다.

    5-3. 멀티 리전 읽기에서 기대가 어긋나는 경우

    글로벌 분산 데이터 구조에서는 리전 간 복제 특성을 이해해야 합니다. 운영자는 한곳에서 테스트하니 괜찮았는데, 해외 리전 사용자 쪽에서는 다른 체감이 나올 수 있거든요. 그래서 저는 가능하면 리전별 테스트 계정이나 지연을 흉내 낸 시나리오를 꼭 만들어봅니다.

    Azure Cosmos DB 일관성 모델 중 Session과 Eventual 비교 다이어그램

    같은 쓰기 이후 Session consistency와 Eventual consistency에서 읽기 결과가 어떻게 다르게 보일 수 있는지 비교한 이미지입니다.

    5-4. 일관성과 캐시를 헷갈리면 답이 안 나옵니다

    이거 진짜 많이 봅니다. 데이터 일관성 문제인지, CDN이나 애플리케이션 캐시 문제인지, 클라이언트 재시도 로직 문제인지 분리하지 않으면 원인 분석이 꼬입니다. 그래서 트러블슈팅은 아래 순서로 가는 걸 추천드립니다.

    1. Cosmos DB 직접 읽기 결과를 확인합니다.
    2. 애플리케이션 서버 내부 로그를 봅니다.
    3. 캐시 계층을 우회한 요청으로 재검증합니다.
    4. 리전별 경로와 장애 조치 상태를 확인합니다.

    6. 검증 방법: 일관성 수준이 정말 기대대로 동작하는지 확인하기

    설정만 바꿨다고 끝이 아닙니다. 검증이 꼭 필요합니다. 특히 NoSQL 환경에서는 “대충 잘 되겠지”가 제일 위험하더라고요. 저는 보통 아래처럼 검증합니다.

    6-1. 기능 검증 체크리스트

    • 쓰기 직후 동일 사용자 읽기가 기대와 맞는지 봅니다.
    • 다른 세션 또는 다른 리전 읽기에서 어느 정도 차이가 나는지 확인합니다.
    • 순서 보장이 필요한 이벤트 데이터는 역전 현상이 없는지 봅니다.
    • 장애 조치 후 동작이 운영 기준에 맞는지 점검합니다.

    6-2. 테스트 관찰 포인트

    검증 항목 확인 질문 의미
    쓰기 후 즉시 읽기 방금 저장한 값이 보이는가? 세션/강한 일관성 체감 확인
    다중 리전 읽기 리전별 결과 차이가 있는가? 글로벌 복제 이해
    이벤트 순서 나중 이벤트가 먼저 보이는가? Consistent Prefix 적합성 확인
    운영 장애 시나리오 장애 후 기대 일관성이 유지되는가? 복구 전략 검증

    실제로 써보니까, 이 검증을 미리 해두면 운영 중 이상 징후가 보여도 훨씬 차분하게 대응할 수 있습니다. 반대로 검증 없이 가면, 문제 생겼을 때 데이터베이스 탓인지 애플리케이션 탓인지 판단이 안 서요.

    Azure Cosmos DB 일관성 모델 검증 결과와 읽기 패턴 대시보드

    일관성 수준 변경 후 읽기 결과와 지연 시간 관찰 포인트를 대시보드 형태로 표현한 이미지입니다.

    7. 어떤 워크로드에 어떤 모델이 맞는가

    정답은 하나가 아닙니다. 그래도 경험상 아래 기준이 꽤 실용적이었습니다.

    7-1. Strong consistency가 어울리는 경우

    • 정합성 오류가 바로 비즈니스 문제로 이어지는 경우
    • 최신 상태 확인이 서비스 핵심인 경우
    • 읽기 지연보다 데이터 정확성이 훨씬 더 중요한 경우

    7-2. Session consistency가 가장 현실적인 경우

    • 일반적인 웹 서비스, 모바일 서비스
    • 사용자가 본인 작업 결과를 곧바로 확인해야 하는 경우
    • 성능과 데이터 일관성의 균형이 필요한 경우

    7-3. Eventual 또는 Consistent Prefix가 맞는 경우

    • 피드, 알림, 통계, 로그 조회
    • 약간의 최신성 지연이 허용되는 경우
    • 글로벌 읽기 성능을 우선하는 경우

    저도 처음엔 모델 이름만 외우려고 했는데, 결국은 워크로드별로 사용자 불만이 어디서 발생하는지를 기준으로 고르는 게 제일 정확했습니다. 이게 훨씬 덜 헷갈립니다.

    8. 정리와 다음 단계

    이번 글의 핵심은 단순합니다. Azure Cosmos DB 일관성 모델은 설정 메뉴에 있는 옵션이 아니라, 서비스의 사용자 경험과 운영 전략을 결정하는 축입니다. Strong, Bounded Staleness, Session, Consistent Prefix, Eventual 각각이 다 의미가 있고요. 무엇을 선택하든 “왜 이걸 고르는지” 설명할 수 있어야 합니다.

    제가 직접 해보니, 대부분의 애플리케이션은 Session consistency에서 출발해도 꽤 안정적으로 설계가 됩니다. 반면 결제나 상태 전이처럼 정확도가 절대적인 구간은 더 강한 모델을 검토해야 했고요. 반대로 피드나 분석 화면은 느슨한 모델이 오히려 운영을 편하게 해주더라고요. 결국 데이터 일관성은 기술 선택이면서 동시에 제품 설계 문제이기도 합니다.

    💡 팁 하나 드리면, 처음부터 완벽한 정답을 찾으려고 하기보다 테스트 시나리오를 먼저 만드세요. 쓰기 직후 읽기, 리전 간 읽기, 장애 조치 후 읽기. 이 세 가지만 검증해도 판단이 훨씬 쉬워집니다.

    다음 글에서는 Azure Cosmos DB 파티셔닝(partitioning, 데이터 분산 저장 단위)과 RU(Request Unit, 요청 처리량 단위) 설계를 같이 다뤄볼 예정입니다. 이전 글에서 다룬 분산 데이터베이스 기본 개념과 함께 보면 훨씬 연결이 잘 되실 거예요.

    Azure Cosmos DB 일관성 모델 5가지 선택 기준 요약 인포그래픽

    Azure Cosmos DB 일관성 수준 선택 기준을 한눈에 비교하는 요약 인포그래픽 이미지입니다.

    FAQ

    Q1. Azure Cosmos DB 일관성 모델에서 기본 선택은 무엇이 무난한가요?

    대부분의 사용자 중심 서비스에서는 Session consistency가 무난한 출발점입니다. 본인 작업 결과를 본인이 바로 보는 흐름이 자연스럽고, 성능과 데이터 일관성의 균형도 괜찮은 편이거든요.

    Q2. Strong consistency를 항상 쓰면 더 좋은가요?

    꼭 그렇지는 않습니다. 데이터 무결성 요구가 매우 강한 구간에는 적합하지만, 모든 읽기에 같은 수준을 강제하면 성능과 운영 유연성 측면에서 부담이 생길 수 있습니다.

    Q3. Eventual consistency는 위험한가요?

    위험하다기보다 용도가 분명합니다. 최종적으로 맞춰지면 되고, 약간의 지연을 허용할 수 있는 피드나 통계 화면에서는 충분히 실용적입니다.

    Q4. Cosmos DB 활용 시 가장 많이 헷갈리는 부분은 뭔가요?

    데이터베이스의 일관성 문제와 캐시 문제를 혼동하는 부분입니다. 둘을 분리해서 봐야 원인 분석이 정확해집니다.