매핑 폭발(Mapping explosion)
매핑 폭발(Mapping explosion)
매핑 폭발은 인덱스가 과도한 수의 필드를 축적해 성능 저하, 메모리 문제, 클러스터 불안정을 초래하는 상황이에요. 문서 구조가 매우 변동적인 동적 매핑 환경에서 각 문서가 새 필드를 도입하며 흔히 발생해요.
출처: 문서
본문
매핑 폭발(mapping explosion)은 인덱스가 과도한 수의 필드를 축적하여 성능 저하, 메모리 문제, 클러스터 불안정을 초래할 때 발생합니다. 이 상황은 문서 구조가 매우 변동적이어서 각 새 문서가 인덱스 매핑에 자동으로 추가되는 추가 필드를 도입하는 동적 매핑(dynamic mapping)을 사용할 때 흔히 발생합니다.
OpenSearch는 문서에서 새 필드를 만나면 동적 매핑을 통해 자동으로 이 필드들의 매핑을 생성합니다. 이 기능은 유연성을 제공하지만 다음과 같은 시나리오에서 문제가 될 수 있습니다.
- 구조가 다양한 로그 데이터: 서로 다른 로그 소스가 고유한 필드를 포함해 필드가 빠르게 늘어날 수 있습니다.
- 사용자 생성 콘텐츠: 사용자가 맞춤형 필드나 속성을 정의할 수 있게 하는 애플리케이션.
- 중첩 객체 구조: 많은 하위 필드를 포함하는 깊이 중첩된 객체가 있는 문서.
- 시계열 데이터: 타임스탬프나 식별자에 기반한 동적 필드 이름을 포함하는 지표 또는 이벤트.
필드 수가 증가하면 여러 문제가 발생할 수 있습니다.
- 필드 매핑 저장에 따른 메모리 소비 증가
- 더 큰 매핑 구조로 인한 쿼리 성능 저하
- 인덱싱 또는 검색 중 잠재적인 메모리 부족(out-of-memory) 오류
- 클러스터 복구 시나리오의 어려움
매핑 제한 설정(Mapping limit settings)
OpenSearch는 매핑 증가의 여러 측면을 제한해 매핑 폭발을 방지하는 여러 인덱스 수준 설정을 제공합니다. 이 설정들은 인덱스 생성 시 구성하거나 기존 인덱스에 대해 갱신할 수 있습니다.
PUT /my-index/_settings
{
"index.mapping.total_fields.limit": 2000
}
다음 표는 사용 가능한 모든 매핑 제한 설정을 나열합니다. 모든 설정은 동적(dynamic)입니다. 자세한 내용은 Dynamic settings를 참고하세요.
| 설정 | 기본값 | 유효 값 | 설명 |
|---|---|---|---|
index.mapping.total_fields.limit |
1000 | [0, ∞) | 인덱스에 허용되는 최대 필드 수를 설정합니다. 일반 필드, 객체 매핑, 필드 별칭(alias)을 모두 포함합니다. 이 제한을 늘리려면 클러스터 리소스를 신중히 고려해야 합니다. 제한을 늘릴 때는 더 큰 쿼리를 수용하도록 indices.query.bool.max_clause_count 설정도 함께 조정하는 것을 고려하세요. |
index.mapping.depth.limit |
20 | [1, 100] | 필드 매핑의 최대 중첩 깊이를 제어합니다. 깊이는 루트 수준부터 시작해 중첩된 객체의 수준을 세어 계산합니다(루트 수준 필드는 깊이 1, 객체 중첩 1단계 안의 필드는 깊이 2 등). |
index.mapping.nested_fields.limit |
50 | [0, ∞) | 인덱스에 허용되는 고유한 nested 필드 유형의 수를 제한합니다. nested 필드는 특별한 처리와 추가 메모리가 필요하므로 이 설정은 과도한 리소스 소비를 방지하는 데 도움이 됩니다. |
index.mapping.nested_objects.limit |
10000 | [0, ∞) | 단일 문서가 모든 nested 필드 유형에 걸쳐 포함할 수 있는 중첩 JSON 객체의 총 수를 제한합니다. 이는 개별 문서가 인덱싱 중 과도한 메모리를 소비하는 것을 방지합니다. |
index.mapping.field_name_length.limit |
50000 | [1, 50000] | 필드 이름의 최대 허용 길이를 설정합니다. 이 설정은 지나치게 긴 필드 이름을 방지해 매핑 크기를 합리적으로 유지하는 데 도움이 될 수 있습니다. |
index.mapper.dynamic |
true | true,false |
새 필드를 매핑에 동적으로 추가할지 여부를 결정합니다. false로 설정하면 통제되지 않는 필드 증가를 방지할 수 있습니다. |
모범 사례(Best practices)
매핑 폭발을 방지하려면 다음 지침을 따르세요.
명시적 매핑 사용(Use explicit mappings)
동적 매핑에 의존하지 말고 가능하면 명시적 매핑을 정의하세요.
PUT /logs
{
"mappings": {
"properties": {
"timestamp": {
"type": "date"
},
"message": {
"type": "text"
},
"level": {
"type": "keyword"
},
"source": {
"type": "keyword"
}
}
}
}
동적 매핑 템플릿 구성(Configure dynamic mapping templates)
동적 템플릿을 사용해 새 필드가 어떻게 매핑될지 제어하세요.
PUT /logs
{
"mappings": {
"dynamic_templates": [
{
"strings_as_keywords": {
"match_mapping_type": "string",
"mapping": {
"type": "keyword"
}
}
}
]
}
}
flat_object 필드 유형 사용(Use the flat_object field type)
임의의 키-값 쌍이 있는 문서에는 동적 매핑을 허용하는 대신 flat_object 필드 유형을 사용하세요.
PUT /products
{
"mappings": {
"properties": {
"name": {
"type": "text"
},
"attributes": {
"type": "flat_object"
}
}
}
}
동적 매핑 비활성화(Disable dynamic mapping)
스키마가 잘 정의된 인덱스에는 동적 매핑을 완전히 비활성화하세요.
PUT /structured-data
{
"mappings": {
"dynamic": "strict",
"properties": {
"id": {
"type": "keyword"
},
"value": {
"type": "double"
}
}
}
}
모니터링 및 유지보수(Monitoring and maintenance)
정기적인 모니터링은 매핑 증가를 조기에 감지하고 클러스터 성능에 영향을 주기 전에 조치를 취하는 데 도움이 됩니다. 다음과 같은 방법으로 필드 매핑을 모니터링할 수 있습니다.
현재 필드 개수 확인(Check the current field count)
인덱스의 필드 수를 모니터링하세요.
GET /my-index/_mapping
또한 Cluster Stats API를 사용해 필드 개수 정보를 얻을 수도 있습니다.
GET /_cluster/stats
문제가 있는 인덱스 식별(Identify problematic indexes)
인덱스 통계를 사용해 필드 수가 많은 인덱스를 찾으세요.
GET /_cat/indices?v&h=index,docs.count,store.size,pri.store.size&s=store.size:desc
사용하지 않는 필드 정리(Clean up unused fields)
동적 매핑이 활성화된 인덱스의 경우 더 제한적인 매핑으로 재인덱싱해 더 이상 필요하지 않은 필드를 정기적으로 검토하고 정리하세요.
매핑 폭발로부터의 복구(Recovery from mapping explosion)
인덱스가 이미 매핑 폭발을 겪었다면 다음을 수행하세요.
- 실제로 필요한 필드를 파악합니다.
- 명시적 매핑과 적절한 제한으로 새 인덱스를 생성합니다.
- Reindex API를 사용해 불필요한 필드를 걸러내며 데이터를 재인덱싱합니다.
- 별칭(alias)을 갱신해 새 인덱스를 가리키게 합니다.
- 마이그레이션이 완료되면 이전 인덱스를 삭제합니다.
POST /_reindex
{
"source": {
"index": "old-index"
},
"dest": {
"index": "new-index"
},
"script": {
"source": "ctx._source.remove('unwanted_field')"
}
}