OpenSearch 무중단 인덱스 교체 전략 (Alias)

2024년 12월 04일

opensearch

# OpenSearch# Alias# 무중단배포

들어가며

검색 인덱스를 운영하다 보면 매핑 변경, 데이터 재색인 등의 이유로 인덱스를 교체해야 하는 상황이 발생합니다. 이때 Alias를 활용하면 다운타임 없이 인덱스를 교체할 수 있습니다.


Alias란?

Alias는 인덱스에 대한 별칭입니다. 애플리케이션은 실제 인덱스명 대신 Alias를 바라보고, Alias가 가리키는 인덱스를 언제든 변경할 수 있습니다.

애플리케이션 → products (alias) → products_v1 (실제 인덱스)

인덱스 네이밍 전략

배치로 전체 데이터를 재색인하는 경우, datetime prefix를 붙여 인덱스를 관리하면 편리합니다.

products_20241204_001
products_20241205_001
products_20241205_002  # 같은 날 재실행 시

이렇게 하면:

  • 인덱스 생성 시점을 명확히 알 수 있음
  • 같은 날 여러 번 실행해도 충돌 없음
  • 정렬하면 시간순으로 나열됨

배치 기반 인덱스 교체 흐름

1. 새 인덱스 생성 (products_20241204_001)
2. 배치로 전체 데이터 색인
3. alias 전환 (products → products_20241204_001)
4. 이전 인덱스 삭제 (products_20241203_001)
# 예시 코드
from datetime import datetime

def create_index_name(prefix: str) -> str:
    today = datetime.now().strftime("%Y%m%d")
    # 같은 날 여러 번 실행 대비 suffix 추가
    return f"{prefix}_{today}_{get_next_suffix()}"

# 배치 실행
new_index = create_index_name("products")  # products_20241204_001
index_all_data(new_index)
swap_alias("products", new_index)
delete_old_indices()

이전 인덱스 정리 (ISM Policy)

이전 인덱스 삭제는 OpenSearch의 ISM (Index State Management) 정책을 활용하여 자동으로 처리합니다.

PUT _plugins/_ism/policies/delete_old_indices
{
  "policy": {
    "description": "오래된 인덱스 자동 삭제",
    "default_state": "active",
    "states": [
      {
        "name": "active",
        "actions": [],
        "transitions": [
          {
            "state_name": "delete",
            "conditions": {
              "min_index_age": "7d"
            }
          }
        ]
      },
      {
        "name": "delete",
        "actions": [
          { "delete": {} }
        ]
      }
    ],
    "ism_template": {
      "index_patterns": ["products_*"],
      "priority": 100
    }
  }
}

이 정책을 적용하면:

  • products_* 패턴에 매칭되는 인덱스에 자동 적용
  • 생성 후 7일이 지난 인덱스는 자동 삭제
  • 수동으로 삭제할 필요 없음

수동 인덱스 교체 과정

1. 초기 상태

# 인덱스 생성
PUT /products_v1
{
  "mappings": {
    "properties": {
      "name": { "type": "text" }
    }
  }
}

# alias 연결
POST /_aliases
{
  "actions": [
    { "add": { "index": "products_v1", "alias": "products" } }
  ]
}

2. 새 인덱스 생성 및 데이터 색인

# 새 매핑으로 인덱스 생성
PUT /products_v2
{
  "mappings": {
    "properties": {
      "name": { "type": "text" },
      "brand": { "type": "keyword" }  # 필드 추가
    }
  }
}

# 데이터 색인 (reindex 또는 애플리케이션에서 직접)
POST /_reindex
{
  "source": { "index": "products_v1" },
  "dest": { "index": "products_v2" }
}

3. Alias 전환 (Atomic)

POST /_aliases
{
  "actions": [
    { "remove": { "index": "products_v1", "alias": "products" } },
    { "add": { "index": "products_v2", "alias": "products" } }
  ]
}

actions 배열 내의 작업들은 **원자적(atomic)**으로 실행됩니다. 즉, 모든 작업이 동시에 적용되어 중간에 alias가 없는 순간이 발생하지 않습니다.

4. 이전 인덱스 정리

# 문제 없으면 이전 인덱스 삭제
DELETE /products_v1

롤백

문제가 발생하면 즉시 이전 인덱스로 전환할 수 있습니다.

POST /_aliases
{
  "actions": [
    { "remove": { "index": "products_v2", "alias": "products" } },
    { "add": { "index": "products_v1", "alias": "products" } }
  ]
}

Alias 조회

# 특정 alias 확인
GET /_alias/products

# 모든 alias 확인
GET /_cat/aliases?v

정리

항목 직접 인덱스 사용 Alias 사용
인덱스 교체 다운타임 발생 무중단
롤백 어려움 즉시 가능
애플리케이션 변경 인덱스명 변경 필요 불필요

참고자료

© 2025, 미나리와 함께 만들었음