Elasticsearch 구성

클러스터

  • ES (Elasticsearch) node 로 이뤄져 있다.
  • 논리적인 연결 = 물리적으로 연결되어 있지 않는다.
  • 동일한 클러스터 이름을 갖는 노드들을 연결한다.

노드

  • 실제 ES 인스턴스가 실행 중인 서버를 의미한다.
  • 설정에 따라 노드를 구분한다.
    • 마스터 노드 : 클러스터 모니터링
    • 데이터 노드 : 실제 데이터 저장
    • 인제스트 노드 : 인덱싱 전 전처리
    • 코디네이팅 : 사용자 요청 처리

인덱스

  • 실제 물리 데이터인 문서들로 이루어짐
  • 클러스터 내 인덱스는 유일하다.
  • 샤드로 구성됨
    • 기본적으로 5개의 샤드로 구성

문서

  • 실제 물리데이터
  • JSON 객체
  • RDB 의 행과 유사
  • 인덱스 생성 가능한 기본 단위
  • 샤드로 분산 저장됨

샤드

  • 인덱스 내의 데이터를 분산 저장
  • 논리적인 분산으로 물리적인 한계 뛰어넘음
  • 인덱스 생성 후 샤드 개수 수정 불가

레플리카

  • 샤드의 복제본
  • 인덱스 생성 시 기본 1세트의 레플리카 생성
  • 장애 발생 시 레플리카로 Fail Over
  • 읽기 작업 시 레플리카 활용 => 읽기 성능 향상
  • 인덱스 생성 후에도 레플리카 개수 조정 가능
  • 원본 샤드가 있는 노드와 다른 노드에 존재

Apache Lucene

샤드 내부에는 루씬 라이브러리와 데이터를 역색인 구조로 저장하는 세그먼트 자료구조가 있다. 세그먼트 내에는 토큰들로 구성되어 있다.

ES 샤드 = 루씬 인덱스 + ES 제공 부가 요소

루씬 인덱스는 IndexWriter, IndexSearcher 를 가지고 있고 내부에 있는 세그먼트에서만 검색이 가능하다.

이러한 루씬 인덱스를 ES 가 샤드로 확장해 분산 검색 및 색인이 가능하게 만들었다.

세그먼트

  • 역색인 파일 그 자체
  • 내부에 역색인된 데이터 존재

커밋 포인트

  • 세그먼트들을 관리하는 자료구조 (루씬 내부에 존재)
  • 색인 요청
    • IndexWriter 세그먼트 생성 -> 커밋 포인트 기록
  • 검색 요청
    • 커밋 포인트 -> 관리 중인 세그먼트

세그먼트들이 점점 늘어나 너무 많은 세그먼트들을 읽어들이면 성능 저하가 발생하기 때문에 백그라운드에서 주기적으로 세그먼트를 병합한다. 이러한 과정을 거치면서 최종적으로 하나의 세그먼트로 병합된다.

색인 작업

  1. 최초 색인
    1. 세그먼트 생성
    2. 생성된 세그먼트 읽어 검색 결과 제공
  2. 추가 색인
    1. 세그먼트 생성
    2. 세그먼트 생성되는 동안 기존 세그먼트 읽어 검색 결과 제공
    3. 세그먼트 생성 후 모든 세그먼트를 읽어 검색 결과 제공
  3. 병합 요청
    1. 기존 세그먼트 복제
    2. 복제된 세그먼트들 병합
    3. 병합되는 동안 기존 세그먼트 읽어 검색 결과 제공
    4. 병합된 세그먼트를 기존 세그먼트와 교체
    5. 교체된 기존 세그먼트 삭제
    6. 병합된 세그먼트 읽어 검색 결과 제공

색인 작업 시 기존 세그먼트에 정보를 추가하거나 변경하지 않는다. 이로 인해 얻는 이점은 아래와 같다.

  • 동시성을 고려하지 않아도 된다.
  • 시스템 캐시를 적극적으로 사용할 수 있다.
  • 캐시 적중률을 높일 수 있다.
  • 역색인 작업 횟수를 줄일 수 있어 리소스 비용이 절감된다.

일부 데이터가 변경되어도 전체 역색인 구조를 다시 만들어야 하는 단점이 있지만 새로운 세그먼트를 추가하는 방식으로 상쇄할 수 있다.

데이터 삭제

데이터 삭제는 세그먼트 내 삭제 배열에 삭제 여부를 표시하는 방식으로 이루어진다. 데이터 검색 시 항상 삭제 배열을 먼저 확인해 삭제된 데이터가 있으면 검색에서 제외하도록 한다. 삭제 배열에 표시된 데이터는 병합 작업 시 물리적인 데이터가 삭제된다.

File I/O

Flush

색인 요청이 들어오면 루씬은 인메모리 버퍼에 요청을 적재한다. 일정한 주기 또는 일정 요청량 이상이 되면 버퍼를 비우며 세그먼트로 생성한다. 이 때 write() 함수를 사용해 커널 시스템 캐시에 데이터를 생성한다. 시스템 캐시에 생성된 시점부터 검색이 가능해진다. IndexSearcher 의 openIfChanged() 함수를 사용한 뒤 검색이 가능하다. 캐시 특성상 데이터가 소실될 수 있는 가능성이 있다.

Commit

실제 디스크에 데이터를 저장하는 fsync() 함수를 사용한다. 디스크 쓰기 작업을 하기 때문에 많은 리소스를 필요로 한다.

Merge

세그먼트 병합 작업 시 위의 Commit 과정이 수행된다.