1. 문제 발생

엘라스틱 서치는 한번 생성한 인덱스의 매핑(테이블 구조)을 변경할 수 없다.

Long ㅁ
string ㅁ

위와 같이 2개의 타입으로 인덱스를 만들었다면, long2개인 인덱스나, 1개의 타입이 추가된 인덱스로 만드려면 무조건 새로 만들어야한다는 문제점이 존재한다.

 

그럼 엘라스틱 서치의 확장성을 위해서 해야하는 전략은 무엇이 있을까?

= 사실 처음부터 제대로 필요한 데이터만 미리 저장하고 인덱스를 수정할 일이 없으면 베스트이긴하다.

하지만 그렇지 못하면, 방법은 크게 5가지 존재한다.

 

2. 문제 원인

  • 엘라스틱 서치는 매핑이 고정되기 때문에 인덱스를 생성한 후에는 필드 타입을 변경할 수 없음.
  • 동적 매핑(Dynamic Mapping)을 사용할 수 있지만, 예상치 못한 데이터 타입 오류가 발생할 가능성이 있음.
  • **필드 개수 제한(1,000개)**이 있기 때문에, 동적 매핑을 사용할 경우 불필요한 필드가 쌓여 인덱스가 비효율적으로 커질 수 있음.
  • 실수로 잘못된 타입을 지정하면 전체 인덱스를 새로 만들어야 하는 부담이 생김.

 

3. 문제 해결책 수립

1. 동적 매핑(Dynamic Mapping)

  • 동적 매핑을 사용하면 새로운 필드가 자동으로 추가되고, 기본 매핑 유형이 설정된다.
  • 하지만 이 방법은 예상치 못한 매핑 오류가 발생할 수 있어 주의가 필요하다.

2. 별도 인덱스 생성 및 데이터 마이그레이션

  • 기존 인덱스를 유지한 상태에서 새로운 매핑을 가진 인덱스를 생성하고, 데이터를 점진적으로 이전하는 방법이다.
  • Zero-downtime 마이그레이션을 지원합니다.
  • 예: index_v1 -> index_v2 로 새 인덱스를 생성하고 데이터 이전 후 기존 인덱스를 삭제한다.

3. 인덱스 에일리어스(Index Alias) 사용

  • 인덱스 에일리어스를 사용하여 클라이언트 측에서 인덱스 이름을 변경하지 않고 새로운 인덱스로 리다이렉션할 수 있다.
  • 예: my_index_alias가 index_v1을 가리키다가, 이후 index_v2로 변경 가능하다.

4. 멀티 인덱스 전략

  • 여러 인덱스를 사용하는 방식으로, 시간 기반 인덱싱(예: 일별/월별)을 통해 확장성을 개선할 수 있다.
  • 오래된 인덱스를 분리 관리하거나, 필요 시 새 인덱스를 추가해도 전체 매핑 구조에 영향을 덜 받는다.

5. 스키마리스(No Schema) 접근

  • 데이터를 다소 유연하게 처리하는 방식으로, JSON 기반 필드를 최대한 활용한다.
  • 하지만 검색 성능과 정확도에 영향이 있을 수 있다.

 

4. 문제 해결

하지만 필자는 이 중 3개의 전략을 선택하게 되었다.

  1. 별도 인덱스 생성 및 데이터 마이그레이션
  2. 인덱스 Alias 사용
  3. 멀티 인덱스 전략

기술 선택의 이유는 실제로 동적 매핑은 비교적 간단하게, 인덱스 템플릿[인덱스 청사진]에서 지정할 수 있지만, 내가 원하지 않는 타입의 인덱스를 저장한다거나.

POST my_index/_doc/1
{
  "price": 10000
}

POST my_index/_doc/2
{
  "price": "10000원"
}

둘은 엄연히 타입이 다르다...

맨 처음 인덱스를 만들 당시 개발자가 실수로 다른 형태로 저장할 경우 인덱스 수정도 안되니 다시 만들어야한다.

실제로 바쁜 상황에서는 가끔 정신줄 놓고 string으로 구현할 걸 숫자가 보인다고 long으로 만드는 경우도 있었다.

거기에 별로 발생할 일은 없지만, 엘라스틱 서치 인덱스 내에 저장할 수 있는 필드의 수는 1000개가 한계인데, 동적 매핑의 경우 이 위험도 발생할 수 있다.

 

설령 위처럼 큰 에러가 발생하지 않더라도, 잘못된 타입을 매핑하면 결국 인덱싱 속도가 느려지고 클러스터 리소스 사용량이 증가한다.

 

마지막 방식인 스키마리스는 이 동적 매핑의 응용으로 사전에 데이터 구조(매핑)을 정의하지 않고 json 기반 동적 매핑을 활용하여 데이터를 유연하게 저장하는 방식을 사용한다.

자연스럽게 남은 선택지는

  1. 별도 인덱스 생성 및 데이터 마이그레이션
  2. 인덱스 Alias 사용
  3. 멀티 인덱스 전략

로 좁혀지게 되었다.

 

 

그러면 이중 1개만 사용해도 되는데 굳이 왜 3개를 다 사용하게 되었는가?

 

사실 1,2번은 세트이다. alias는 간단히 말하면 명찰이다.

예를 들어 노드 a1,a2,a3가 있다 이들은 모두 a라는 명찰사용하고 있다고 생각해보자, 그럼 손님은 a1,2,3를 같은 a라는 직원으로 여기게 된다.

 

손님 = 클라이언트

a = 노드의 별명

a1,2,3 = 실제 노드이름

 

클라이언트인 우리(스프링 프로젝트)의 입장에서는 결국 a에게 데이터를 달라고 하면되고, a1,a2,a3에 있는 데이터를 a라는 이름으로 받아올 수 있게된다.

 

그럼 메인 의사 결정인, 확장성의 이야기로 돌아가보자, alias로 2개의 노드를 1개의 대상으로 볼 수 있다면,

a1 = a

string a
long b

위와 같은 상황에서, a에 새로 필요한 인덱스 형태인 a2를 추가해보자

a2, a1 = a

string a
long b
string c

클라이언트 입장에서는 a에 a2가 추가되었어도 결국은 a로 보이고 a1이 없어져도 결국 a로만 보인다.

즉, 필요한 형태인 a2를 만들고 a1의 내용을 복사한 후 a2을 지우면, 클라이언트는 실상 코드 변경없이도 노드 연결을 유지할 수 있다.

 

이렇게

  1. 별도 인덱스 생성 및 데이터 마이그레이션
  2. 인덱스 Alias 사용

를 선택하게 되었다.

 

그럼 3번인 멀티 인덱스 전략은 왜 나왔는가, 위는 데이터 수정이 필요할 경우의 확장성이라면 아래는 말 그대로 데이터를 효율적으로 사용하기 위한 확장성이라 보면된다.

 

멀티 인덱스는 예시로 이야기하면, 시간 기반 인덱싱 처럼(일별, 월별로 데이터를 나눠서 저장) 데이터를 시간, 특징을 기준으로 나눠 저장하면 이미 분업이 되어 있으므로 특정 데이터 예를 들면, 1달간의 데이터만 요구된다면, 전체 다 저장된 인덱스에서 접근하기 보단 근 1달치만 저장된 인덱스를 가져오면 더 편하다.

 

인덱스 관리에도 유리하고 새 인덱스를 추가해도 전체 매핑 구조에 영향이 덜 미친다.

+ Recent posts