코드몽키
Elasticsearch 기본 개념 본문
회사 프로젝트에서 전국 단위 주소 검색을 지원하는 모듈을 개발한 경험이 있다. 데이터 규모가 방대하고 실시간 자동완성 기능이 요구되는 상황에서, 초기에는 RDBMS 기반으로 서비스를 구현했으나 응답 속도가 느리고 검색 정확도 역시 한계가 있었다. 특히 대량 데이터에 대한 부분 일치 검색과 형태소 분석이 필요한 경우, RDBMS의 LIKE 검색 방식은 성능 저하가 뚜렷했다. 이를 해결하기 위해 Elasticsearch를 학습하여 시스템에 적용하였고, 적절한 분석기 설정과 데이터 최적화를 통하여 성능과 검색 품질을 모두 개선할 수 있었다. 본 포스팅에서는 해당 과정에서 학습한 Elasticsearch의 핵심 개념과 구조를 정리한다.
엘라스틱 서치(Elasticsearch)는 엘라스틱 스택(Elastic Stack)의 중심이 되는 분산형 분석 저장소이자 Apache Lucene을 기반으로 만들어진 검색 엔진으로 데규모 데이터를 저장하고 검색/분석 할 수 있도록 설계되었다.

아래의 검색 엔진 트렌드 스코어 그래프를 확인 하면 얼마나 Elasticsearch가 방대하게 사용되는 지 알 수 있다. 이 그래프 하나만으로도 Elasticsearch가 현대 데이터 인프라에서 얼마나 중요한 위치를 차지하고 있는지 체감이 된다.

이제 엘라스틱 서치를 기본적으로 사용하기 위한 기본 개념들에 대해서 설명하겠다.
Cluster
Elasticsearch 클러스터는 데이터를 저장하는 노드 그룹으로 구성된다. 클러스터와 함께 실행되는 노드 수와 가상 또는 물리 서버의 IP 주소를 지정 하여 elasticsearch.yml 파일에 포함되어 있다. Elasticsearch 클러스터의 노드는 서로 연결되어 있으며 각 노드에 인덱스를 공유하는 샤드로 이루어져 있다.

Node
Elasticsearch에서 노드는 클러스터의 일부로 작동하는 인스턴스를 말하며, 물리적인 서버가 아니라 하나의 프로세스 단위이다. 한 서버에서도 여러 노드를 실행할 수 있다.
| 종류 | 역할 |
| 마스터 노드(Master Node) | 클러스터 상태를 관리하고 인덱스 생성, 샤드 배치 등 클러스터 전반의 작업을 담당 |
| 데이터 노드(Data Node) | 실제 색인과 검색을 수행하며 샤드를 저장하는 역할 |
| 클라이언트 노드(Client Node) | 요청을 데이터 노드로 분배하고 결과를 집계하는 로드 밸런서 역할 |
노드의 역할은 elasticsearch.yml 파일의 node.roles 항목이나 실행 시 커맨드라인 옵션으로 지정할 수 있으며, 특별히 지정하지 않으면 기본적으로 마스터와 데이터 역할을 모두 갖게 된다.
Index
Elasticsearch에서 인덱스(Index)는 데이터를 논리적으로 모아둔 저장 단위이다. RDBMS의 테이블(Table)과 비슷한 개념으로, 색인된 JSON 문서(Document)를 담고 있으며, 검색과 집계 등 모든 작업의 기본 단위가 된다. 각 인덱스는 내부적으로 여러 샤드(Shard)로 나뉘어 분산 저장되며, 자체적인 매핑(Mapping)과 설정(Settings)을 가질 수 있다. 쉽게 비유하면, 한 권의 책이 인덱스이고, 책의 페이지가 샤드, 페이지 안의 문단이 문서라고 생각하면 된다.
Shard
Elasticsearch에서 샤드(Shard)는 인덱스를 물리적으로 나눈 데이터 저장 단위이다. 인덱스가 너무 커져서 한 노드에 모두 담기 어려울 때, 데이터를 여러 샤드로 나누어 여러 노드에 분산 저장함으로써 병렬 작동하게 하여 검색과 색인 성능을 높힐 수 있다. 샤드는 프라이머리 샤드(Primary Shard)와 레플리카 샤드(Replica Shard)로 나누어 저장 함으로써 단순히 성능의 개선 뿐만 아니라 고가용성과 서비스의 안정적인 운영이 가능 하게한다. 프라이머리 샤드는 원본 데이터를 저장하는 주 샤드로, 모든 색인 작업이 우선적으로 여기에 기록된다. 레플리카 샤드는 프라이머리 샤드의 복제본으로, 다른 노드에 저장되어 장애 발생 시 데이터 손실을 방지하고, 검색 부하를 분산시키는 역할을 한다.

위의 그림처럼 서로 교차해서 각 프라이머리 샤드의 복제본(레플리카 샤드)이 다른 노드에 배치된다.
이렇게 하면 특정 노드가 장애로 다운되더라도, 해당 노드의 프라이머리 샤드를 다른 노드의 레플리카 샤드로 대체하여 서비스가 중단 없이 계속 운영될 수 있게 한다. 또한 검색 요청 시 프라이머리와 레플리카가 병렬로 응답할 수 있어, 전체적인 검색 처리 속도도 향상된다.
즉, 샤드의 교차 배치는 고가용성 확보와 부하 분산이라는 두 가지 핵심 목표를 동시에 달성하는 Elasticsearch의 중요한 설계 원리라고 할 수 있다.
Inverted Index(역 인덱스)
Elasticsearch를 이해하려면 역 인덱스(Inverted Index) 개념은 핵심 중에 핵심 이라고 할 수 있다. 왜냐하면, 역 인덱스 구조 덕분에 Elasticsearch의 빠른 검색 성능이 가능 한 이유이다. 일반적인 RDBMS같은 경우엔 정방향 인덱스 방식을 사용하여 데이터를 검색한다. (예: row 인덱스 값 -> 해당 row의 내용) 이 방식은 특정 문서를 index 값으로 찾을 땐 빠르지만 특정 단어 "서울시" 이라는 모든 row를 찾으려면 모든 문서를 검색하는 Full Scan 과정이 필요하여 데이터가 많아 지면 많아질 수록 성능은 저하된다.
역 인덱스는 이 구조를 반대로 뒤집은 것이다. Elasticsearch는 단어 -> 해당 단어가 등장하는 문서 ID 목록으로 조회하여 해당 단어가 들어간 모든 문서를 즉시 찾을 수 있고, AND 같은 복합 조건도 빠르게 교집합 연산으로 처리할 수 있다. 각 샤드 내부에 Lucene 엔진이 있고 이 엔진이 바로 역 인덱스를 사용해 대용량 텍스트 검색이 초고속으로 가능 하도록 한다.