[Elasticsearch-01] Elasticsearch 구성과 Apache Lucene
by Mingdo
Elasticsearch 구성
클러스터
- ES (Elasticsearch) node 로 이뤄져 있다.
- 논리적인 연결 = 물리적으로 연결되어 있지 않는다.
- 동일한 클러스터 이름을 갖는 노드들을 연결한다.
노드
- 실제 ES 인스턴스가 실행 중인 서버를 의미한다.
- 설정에 따라 노드를 구분한다.
- 마스터 노드 : 클러스터 모니터링
- 데이터 노드 : 실제 데이터 저장
- 인제스트 노드 : 인덱싱 전 전처리
- 코디네이팅 : 사용자 요청 처리
인덱스
- 실제 물리 데이터인 문서들로 이루어짐
- 클러스터 내 인덱스는 유일하다.
- 샤드로 구성됨
- 기본적으로 5개의 샤드로 구성
문서
- 실제 물리데이터
- JSON 객체
- RDB 의 행과 유사
- 인덱스 생성 가능한 기본 단위
- 샤드로 분산 저장됨
샤드
- 인덱스 내의 데이터를 분산 저장
- 논리적인 분산으로 물리적인 한계 뛰어넘음
- 인덱스 생성 후 샤드 개수 수정 불가
레플리카
- 샤드의 복제본
- 인덱스 생성 시 기본 1세트의 레플리카 생성
- 장애 발생 시 레플리카로 Fail Over
- 읽기 작업 시 레플리카 활용 => 읽기 성능 향상
- 인덱스 생성 후에도 레플리카 개수 조정 가능
- 원본 샤드가 있는 노드와 다른 노드에 존재
Apache Lucene
샤드 내부에는 루씬 라이브러리와 데이터를 역색인 구조로 저장하는 세그먼트 자료구조가 있다. 세그먼트 내에는 토큰들로 구성되어 있다.
ES 샤드 = 루씬 인덱스 + ES 제공 부가 요소
루씬 인덱스는 IndexWriter, IndexSearcher 를 가지고 있고 내부에 있는 세그먼트에서만 검색이 가능하다.
이러한 루씬 인덱스를 ES 가 샤드로 확장해 분산 검색 및 색인이 가능하게 만들었다.
세그먼트
- 역색인 파일 그 자체
- 내부에 역색인된 데이터 존재
커밋 포인트
- 세그먼트들을 관리하는 자료구조 (루씬 내부에 존재)
- 색인 요청
- IndexWriter 세그먼트 생성 -> 커밋 포인트 기록
- 검색 요청
- 커밋 포인트 -> 관리 중인 세그먼트
세그먼트들이 점점 늘어나 너무 많은 세그먼트들을 읽어들이면 성능 저하가 발생하기 때문에 백그라운드에서 주기적으로 세그먼트를 병합한다. 이러한 과정을 거치면서 최종적으로 하나의 세그먼트로 병합된다.
색인 작업
- 최초 색인
- 세그먼트 생성
- 생성된 세그먼트 읽어 검색 결과 제공
- 추가 색인
- 세그먼트 생성
- 세그먼트 생성되는 동안 기존 세그먼트 읽어 검색 결과 제공
- 세그먼트 생성 후 모든 세그먼트를 읽어 검색 결과 제공
- 병합 요청
- 기존 세그먼트 복제
- 복제된 세그먼트들 병합
- 병합되는 동안 기존 세그먼트 읽어 검색 결과 제공
- 병합된 세그먼트를 기존 세그먼트와 교체
- 교체된 기존 세그먼트 삭제
- 병합된 세그먼트 읽어 검색 결과 제공
색인 작업 시 기존 세그먼트에 정보를 추가하거나 변경하지 않는다. 이로 인해 얻는 이점은 아래와 같다.
- 동시성을 고려하지 않아도 된다.
- 시스템 캐시를 적극적으로 사용할 수 있다.
- 캐시 적중률을 높일 수 있다.
- 역색인 작업 횟수를 줄일 수 있어 리소스 비용이 절감된다.
일부 데이터가 변경되어도 전체 역색인 구조를 다시 만들어야 하는 단점이 있지만 새로운 세그먼트를 추가하는 방식으로 상쇄할 수 있다.
데이터 삭제
데이터 삭제는 세그먼트 내 삭제 배열에 삭제 여부를 표시하는 방식으로 이루어진다. 데이터 검색 시 항상 삭제 배열을 먼저 확인해 삭제된 데이터가 있으면 검색에서 제외하도록 한다. 삭제 배열에 표시된 데이터는 병합 작업 시 물리적인 데이터가 삭제된다.
File I/O
Flush
색인 요청이 들어오면 루씬은 인메모리 버퍼에 요청을 적재한다. 일정한 주기 또는 일정 요청량 이상이 되면 버퍼를 비우며 세그먼트로 생성한다. 이 때 write() 함수를 사용해 커널 시스템 캐시에 데이터를 생성한다. 시스템 캐시에 생성된 시점부터 검색이 가능해진다. IndexSearcher 의 openIfChanged() 함수를 사용한 뒤 검색이 가능하다. 캐시 특성상 데이터가 소실될 수 있는 가능성이 있다.
Commit
실제 디스크에 데이터를 저장하는 fsync() 함수를 사용한다. 디스크 쓰기 작업을 하기 때문에 많은 리소스를 필요로 한다.
Merge
세그먼트 병합 작업 시 위의 Commit 과정이 수행된다.
Subscribe via RSS