MongoDB 성능 병목 현상 방지: 선제적 접근 방식

더 나은 스키마 설계, 복합 인덱스, 쿼리 계획 및 실용적인 모니터링 알림을 통해 MongoDB 병목 현상을 예방하세요.

MongoDB 성능 병목 현상 예방: 사전 대응 접근법

MongoDB 성능 병목 현상은 일반적으로 데이터베이스가 완전히 실패하기 훨씬 전에 느린 페이지, 증가하는 대기열 또는 과부하된 디스크로 나타납니다. 쿼리 중심으로 문서를 설계하고, 실제 워크로드에 인덱싱하며, 초기에 올바른 지표를 관찰함으로써 많은 문제를 예방할 수 있습니다.

이 가이드는 느린 쿼리, 복제 지연, 큰 작업 세트 및 리소스 압박과 같은 일반적인 문제 지점에 초점을 맞춥니다.

기초: 최적화된 스키마 설계

MongoDB의 유연한 스키마는 강력한 기능이지만, 쿼리 효율성과 데이터 지역성에 직접적인 영향을 미치는 신중한 설계 선택이 필요합니다. 잘못된 스키마 설계는 인덱싱과 관계없이 비용이 많이 드는 조회나 큰 문서 읽기를 초래할 수 있습니다.

1. 임베딩과 참조의 균형

가장 중요한 스키마 결정은 관련 데이터를 언제 임베딩(동일한 문서에 저장)할지와 언제 참조(별도 문서에 저장)할지를 결정하는 것입니다.

임베딩 (높은 읽기 지역성)

임베딩은 임베드된 데이터가 부모 문서와 함께 자주 읽히고 임베드된 데이터에 대한 업데이트가 드문 일대소수 또는 일대다 관계에 선호됩니다.

  • 이점: 완전한 데이터를 검색하는 데 필요한 쿼리 수를 줄여 읽기 성능을 향상시킵니다.
  • 예시: 사용자의 현재 배송 주소를 user 문서 내에 직접 저장합니다.

참조 (높은 쓰기 빈도 또는 대용량 데이터)

참조는 임베드된 목록이 무제한으로 커지거나 관련 데이터가 크거나 부모 문서와 독립적으로 자주 업데이트되는 일대다 관계에 필요합니다.

  • 이점: 문서 증가를 방지하고 각 업데이트가 다시 작성해야 하는 데이터 양을 줄입니다.
  • 예시: 모든 주문을 고객 문서 내에 임베드하는 대신 customer_id를 참조하는 order 문서를 저장합니다.

팁: 16MB BSON 문서 크기 제한에 근접하는 문서를 만들지 마십시오. I/O 비용 증가로 인해 이 제한에 도달하기 훨씬 전에 성능 저하가 자주 발생합니다.

2. 적절한 데이터 유형 선택

필드가 올바른 BSON 데이터 유형을 사용하여 일관되게 저장되도록 하십시오. 날짜나 숫자 ID에 문자열을 사용하면 성능과 인덱싱이 심각하게 저하됩니다.

필드 용도 권장 BSON 유형 근거
타임스탬프/날짜 ISODate 효율적인 범위 쿼리 및 시간 기반 인덱싱 허용
고유 식별자 ObjectID 또는 Long/Int 작은 인덱스 공간과 빠른 비교 보장
통화/정밀 값 Decimal128 Double에서 흔한 부동 소수점 오류 방지

효과적인 인덱싱 전략

인덱스는 MongoDB에서 쿼리 최적화를 위한 가장 강력한 도구입니다. 인덱스를 사용하면 데이터베이스가 전체 컬렉션을 스캔(COLLSCAN)하지 않고도 데이터를 빠르게 찾을 수 있으며, 이는 성능 저하의 대표적인 지표입니다.

1. explain()을 사용한 느린 쿼리 식별

인덱스를 추가하기 전에 워크로드를 프로파일링하여 느린 작업을 식별하십시오. explain() 메서드를 사용하여 쿼리 계획을 분석합니다.

db.collection.find({ 
  status: "active", 
  priority: { $gte: 3 }
}).sort({ created_at: -1 }).explain("executionStats")

목표: winningPlanIXSCAN(인덱스 스캔)을 보여주고 totalDocsExaminednReturned 값에 가까운지 확인합니다.

2. 복합 인덱스를 위한 ESR 규칙

복합 인덱스(여러 필드에 대한 인덱스)를 생성할 때 Equality, Sort, Range (ESR) 규칙을 따라 효율성을 극대화하십시오:

  1. Equality: 정확한 일치에 사용되는 필드($eq, $in). 이들을 먼저 배치합니다.
  2. Sort: 결과 정렬에 사용되는 필드(.sort()). 이들을 두 번째로 배치합니다.
  3. Range: 범위 쿼리에 사용되는 필드($gt, $lt, $gte, $lte). 이들을 마지막에 배치합니다.
// 쿼리: find({ user_id: 123, type: "payment" }).sort({ date: -1 }).limit(10)
// ESR을 따르는 인덱스:
db.transactions.createIndex({ 
  user_id: 1, 
  type: 1, 
  date: -1 
})

경고: 인덱스는 메모리와 디스크 공간을 소비하며, 모든 쓰기 작업이 영향을 받는 모든 인덱스를 업데이트해야 하므로 쓰기 성능에 불이익을 줍니다. 중요한 쿼리에서 자주 사용되는 인덱스만 생성하십시오.

3. 부분 인덱스 및 TTL 인덱스 활용

  • 부분 인덱스: 필터를 지정하여 컬렉션의 문서 하위 집합만 인덱싱합니다. 이렇게 하면 인덱스 크기와 쓰기 불이익이 크게 줄어듭니다.
    // 'archived'가 false인 문서만 인덱싱
    db.logs.createIndex( { timestamp: 1 }, { partialFilterExpression: { archived: false } } )
    
  • TTL(Time-to-Live) 인덱스: 특정 기간 후에 문서를 자동으로 만료시킵니다. 이는 로그, 세션 저장소 또는 임시 캐시의 데이터 증가를 관리하여 디스크 공간 병목 현상을 방지하는 데 중요합니다.

사전 예방적 모니터링 및 알림

예방을 위해서는 데이터베이스의 운영 상태를 지속적으로 파악해야 합니다. 포괄적인 모니터링을 통해 지연 시간의 갑작스러운 급증이나 캐시 성능 저하와 같은 새로운 문제가 사용자에게 영향을 미치기 전에 포착할 수 있습니다.

지속적으로 추적해야 할 주요 지표

1. 쿼리 성능

95번째 및 99번째 백분위수(P95/P99) 쿼리 지연 시간을 모니터링합니다. 여기서 갑작스러운 증가는 비효율적인 쿼리, 인덱스 누락 또는 하드웨어 경합을 나타냅니다.

2. 캐시 사용률 (WiredTiger)

캐시 읽기, 더티 바이트, 축출 활동 및 디스크 읽기 지연 시간을 추적합니다. MongoDB의 WiredTiger 스토리지 엔진은 내부 캐시에 크게 의존하지만, 단일 보편적인 적중률 임계값은 너무 단순합니다. 캐시 적중률 하락, 축출 압력 증가 또는 정상 트래픽 중 지속적인 디스크 읽기는 작업 세트가 더 이상 메모리에 편안하게 맞지 않음을 의미할 수 있습니다.

3. 복제 상태

복제 지연은 복제 세트에서 모니터링하는 데 중요합니다. 주요 지표는 Oplog Window(작업 로그의 크기)입니다. 감소하는 Oplog Window 또는 높은 복제 지연(초 단위로 측정)은 세컨더리가 따라잡는 데 어려움을 겪고 있음을 나타내며, 이는 느린 읽기, 오래된 데이터 또는 너무 뒤처진 경우 세컨더리가 따라잡을 수 없는 가능성으로 이어질 수 있습니다.

4. 시스템 리소스 및 잠금

  • CPU 및 I/O 대기: 높은 I/O 대기는 종종 잘못된 인덱싱이나 불충분한 캐시 크기를 나타냅니다.
  • 동시성 압박: 대기 중인 읽기/쓰기, 장기 실행 작업 및 스토리지 엔진 티켓을 관찰합니다. 최신 MongoDB는 이전의 전역 잠금 버전처럼 작동하지 않으므로, 하나의 일반적인 잠금 비율보다는 현재 대기 및 지연 시간 지표에 집중하십시오.

실행 가능한 알림 설정

즉각적인 조치를 가능하게 하려면 적절한 임계값으로 알림을 구성하십시오:

문제 트리거 사전 예방적 임계값
P95 쿼리 지연 시간 5분 동안 서비스 목표 초과
WiredTiger 캐시 압박 축출 및 디스크 읽기가 정상 기준선 이상 상승
복제 지연 읽기 부실 또는 장애 조치 허용 오차 초과
사용 가능한 디스크 공간 확장 및 백업 안전 마진 아래로 하락

도구: db.serverStatus()를 통한 내장 모니터링 또는 MongoDB Atlas Monitoring, MongoDB Exporter와 함께 Prometheus, Datadog과 같은 특수 플랫폼을 활용하여 상세한 과거 추세 분석을 수행하십시오.

결론

MongoDB 성능 병목 현상을 예방하는 것은 지속적인 순환 과정입니다: 액세스 패턴에 맞게 데이터를 모델링하고, explain("executionStats")로 쿼리 계획을 확인하며, 자체 기준선의 변화에 대해 알림을 설정하십시오. 사용자에게 가장 큰 영향을 미치는 쿼리부터 시작한 다음, 트래픽이 문제를 강제하기 전에 인덱스와 문서 증가를 검토하십시오.