본문 바로가기
ES

Elasticsearch 데이터는 어떻게 저장되고 검색될까?

by 비타민찌 2025. 9. 19.
728x90

Elasticsearch 데이터는 어떻게 저장되고 검색될까? 

Elasticsearch 구조

 

 

대규모 로그 처리 환경에서는 매일 수십억 건의 데이터가 발생합니다.
이러한 데이터는 단순 보관이 아니라 검색과 분석까지 가능해야 하며,

안정적으로 수평 확장이 가능한 구조가 필요합니다.

Elasticsearch는 이러한 요구에 맞춰 로그 수집과 분석에 널리 사용되는 분산 검색 엔진입니다.
이번 글에서는 Elasticsearch 내부에서 데이터가 어떻게 저장되고, 검색되는지를 구조적으로 살펴보겠습니다.

 

 

클러스터 기본 구조
  • 데이터 노드 3대를 가진 Elasticsearch 클러스터를 가정합니다.
    • 마스터 후보는 별도(여기선 설명 단순화 위해 생략), 코디네이터 역할은 모든 노드 가능
  • 인덱스(products): number_of_shards: 3, number_of_replicas: 1 → 총 6개 샤드(Primary 3 + Replica 3)
  • 문서 특징: 문자열은 text + keyword 멀티필드, 숫자/날짜는 집계·정렬용 DocValues 활성화

 

 

1. Document 저장 과정

(1) JSON Document 입력

Elasticsearch는 기본적으로 JSON 문서 단위로 데이터를 받습니다.
예를 들어 상품 데이터를 하나 저장한다고 해봅시다.

 

POST /products/_doc/1
{
  "name": "크림치즈",
  "price": 4900,
  "tags": ["food","cheese"],
  "ts": "2025-09-01"
}

 

이 요청을 받은 노드는 Coordinating Node 역할을 하며,

문서 ID → Primary Shard 라우팅을 계산한 뒤 해당 샤드가 위치한 데이터 노드로 전달합니다.

 

 

(2) _source 보관

Elasticsearch는 입력받은 원본 JSON을 _source라는 내부 필드에 그대로 저장합니다.
Lucene은 이를 디스크에 기록할 때 내부적으로 압축을 적용해 저장 공간을 최적화할 수 있습니다.

(_source는 검색 결과 반환 시 기본으로 사용되지만, 일부 환경에서는 stored_fields나 doc_values만 활용하도록 설정하기도 합니다.)

 

 

(3) Mapping 기반 색인

Elasticsearch는 인덱스마다 매핑(Mapping) 이라는 스키마 정보를 가집니다.

  • name: text → 형태소 분석기로 "크림", "치즈"로 분리
  • name.keyword: keyword → "크림치즈" 문자열 그대로 저장
  • price: integer → 숫자 값 그대로 저장
  • tags: keyword[] → "food", "cheese"
  • ts: date → 내부적으로 epoch millisecond 값 변환

즉, 문서가 단순히 보관되는 게 아니라 검색하기 좋은 구조로 변환됩니다.

 

 

(4) Lucene Segment 생성

실제 저장을 담당하는 Lucene이 데이터를 Segment 파일에 저장합니다.

Segment에는 두 가지 주요 구조가 있습니다.

  • Inverted Index (역색인) → 검색용
    "크림" → doc-1 "치즈" → doc-1
  • DocValues → 정렬/집계용
    price = 4900 ts = 1756694400000

Segment는 불변(immutable) 구조입니다. 따라서 업데이트/삭제 시에는 새로운 Segment가 만들어지고,

기존 문서는 삭제 플래그만 남습니다.

운영 환경에서는 merge 작업이 중요한데, 작은 Segment들을 합치며 삭제된 문서를 정리합니다. 다만 merge는 디스크 IO 부하를 유발하기 때문에 refresh/merge 튜닝이 성능 최적화의 핵심 포인트가 됩니다.

 

 

(5) Shard & Replica 분산 저장

Elasticsearch의 인덱스는 여러 개의 Shard로 나뉘며, 각 Shard는 Lucene 인덱스입니다.

  • Primary Shard에 먼저 저장 → 인덱싱 성공
  • Replica Shard로 복제 → 모든 Replica 반영 성공 시 ACK 반환

즉, 문서 저장 → Segment → Shard → Node 순서로 안전하게 분산 저장되며,

장애 발생 시에도 Replica에서 데이터를 복구할 수 있습니다.


2. 검색 과정

(1) 사용자의 검색 요청

 
GET /products/_search
{
  "query": { "match": { "name": "치즈" } }
}

 

(2) Coordinating Node

검색 요청을 받은 노드는 Coordinating Node 역할을 하며,
해당 인덱스의 모든 Shard에 대해 Primary 또는 Replica 중 하나를 선택해 쿼리를 실행합니다.

 

 

(3) Shard 단위 검색

각 Shard에서는 Lucene이 역색인(Inverted Index)을 통해 "치즈"라는 term이 포함된 Document ID들을 빠르게 찾습니다.

 

 

(4) 결과 병합 및 정렬

Coordinating Node는 Shard별로 반환된 결과를 merge & sort 하고, 요청한 size 만큼 상위 N개 문서를 추립니다.

 

 

(5) _source 반환

마지막으로 _source에 저장해둔 원본 JSON을 꺼내 사용자에게 반환합니다.

즉, 검색은 Lucene의 역색인 구조를 통해 수행되지만, 최종적으로는 원본 JSON이 그대로 돌아옵니다.

 

 

3. 저장 & 검색 구조

저장 흐름
 
 
JSON Document
   → _source 보관
   → Mapping 기반 분석 (text/keyword/number/date)
   → Lucene Segment 저장 (Inverted Index + DocValues)
   → Shard 배치 (Primary → Replica)
 
검색 흐름

사용자 Query
   → Coordinating Node
   → 각 Shard 검색 (Lucene Inverted Index)
   → 결과 병합/정렬
   → _source 반환
 
 
 

4. 정리

모든 문서는 Lucene Segment 단위로 변환되어 저장되고, 검색 시 역색인 구조를 활용해 빠르게 수행 됩니다.
Shard & Replica 구조로 분산 저장되어 확장성과 내결함성도 보장합니다.
 
실제 운영에서는 Shard 개수 설계, Mapping 관리, refresh/merge 튜닝이 성능과 안정성의 핵심입니다. 
저장 흐름에는 _source, Lucene Buffer, Translog, Segment가 모두 관여하므로, 장애 복구나 성능 최적화 시 반드시 고려해야 합니다.
 
 
 
저장
저장 → 문서 → Segment → Shard → Node → Cluster
 

 

검색

검색 → 쿼리 → Shard fan-out → 병합 → _source 반환

 

 


대규모 로그 처리 환경에서 Elasticsearch를 안정적으로 운영하려면,

이런 기본적인 요소들을 올바르게 이해하는 것이 기본 입니다 :)

 

 

Document 저장 과정 Elasticsearch: Mapping → The _source field

Index, Shard, Replica 개념 Elasticsearch: Index modules → Shard allocation

Cluster, Node, Shard 관계 Elasticsearch: Cluster, nodes, and shards

Refresh & Flush Elasticsearch: Refresh API

Indexing lifecycle (Document → Buffer → Segment → Commit → Merge) 
Elasticsearch: How data is indexed

728x90

댓글