검색 알고리즘보다 메모리, 디스크, 세그먼트, 보존 정책을 다루는 일이 Elasticsearch 운영의 대부분을 차지합니다.
운영이 다루는 자원
Elasticsearch는 Apache Lucene 기반의 분산 검색·분석 엔진입니다. 운영에서 응답 시간을 가르는 것은 검색 기능보다 자원 배분입니다. JVM 힙과 파일 시스템 캐시의 균형, 샤드 수, 인덱스 수명 주기 정책이 성능을 좌우합니다.
기본 설정을 유지한 채 적재량이 늘면 운영 문제가 생길 수 있습니다. 대표 증상은 잦은 OOM(Out of Memory) 종료, 가비지 컬렉션(GC, Garbage Collection)으로 인한 멈춤, 색인 지연입니다. 힙, 캐시, 세그먼트, 보존 정책을 함께 점검해야 합니다.
JVM 힙과 파일 시스템 캐시
힙 메모리는 너무 작아도, 너무 커도 문제를 만듭니다. 검색 엔진 데몬이 JVM 위에서 돌기 때문에 힙 크기가 안정성의 출발점입니다.
기준은 두 가지입니다. 첫째는 50% 룰입니다. 물리 RAM의 절반 이하만 힙(-Xms, -Xmx)에 할당하고, 나머지 절반은 운영체제가 파일 시스템 캐시로 쓰게 둡니다. 이 캐시가 Lucene 세그먼트를 디스크에서 읽는 속도를 결정하므로 검색 지연에 직접 영향을 줍니다.
둘째 기준은 32GB 경계입니다. 힙을 32GB 부근 이상으로 키우면 JVM이 압축된 객체 포인터(Compressed Object Pointers) 대신 64비트 포인터를 씁니다. 이때 객체 메모리 오버헤드가 약 1.5배 늘어납니다. 따라서 힙을 늘려도 저장 가능한 객체 수가 줄 수 있습니다(Elasticsearch 공식 권고).
GC는 Elasticsearch 7 이상에서 멈춤 시간이 짧은 G1GC(Garbage First Garbage Collector)가 기본값입니다. 운영 중 힙이 동적으로 늘었다 줄면 무거운 멈춤이 생기므로, 최소 힙(-Xms)과 최대 힙(-Xmx)을 같은 값으로 고정합니다.
# jvm.options
-Xms16g
-Xmx16g힙 사용량이 한계에 가까워지면 Elasticsearch는 서킷 브레이커로 위험한 요청을 미리 거부합니다. 이는 노드가 OOM으로 죽는 것보다 일부 요청 실패를 택하는 보호 장치입니다.
색인 성능과 refresh interval
대량 색인(bulk) API로 데이터를 밀어 넣을 때는 실시간 검색 가시성을 잠시 양보합니다. refresh는 새 문서를 검색 가능한 상태로 만드는 작업입니다. 자체 관리형 Elastic Stack은 최근 30초 안에 검색된 인덱스를 기본 1초마다 갱신합니다(Elastic 색인 튜닝 문서).
refresh가 잦으면 작은 세그먼트가 계속 생기고, 백그라운드 세그먼트 병합(Merge) 비용이 커집니다. 그래서 대량 적재 구간에서는 refresh 주기를 늘리거나 끄고, 복제본(replica) 수를 0으로 낮춰 쓰기 부하를 줄입니다.
다음 예시는 Elasticsearch Console의 HTTP 요청 형식입니다.
PUT /logs-2026.06/_settings
{
"index": {
"refresh_interval": "30s",
"number_of_replicas": 0
}
}적재가 끝나면 refresh 주기와 복제본 수를 운영값으로 되돌립니다. 이 작업으로 검색 가시성과 가용성을 회복합니다. 한 인덱스에 대량 적재와 실시간 검색을 동시에 집중하면 두 작업의 성능이 모두 나빠집니다. 워크로드를 시간대나 인덱스별로 나누는 편이 안전합니다.
검색 성능과 필터 컨텍스트
질의는 점수가 필요한 쿼리 컨텍스트와 예/아니오만 판정하는 필터 컨텍스트로 나뉩니다. 이 구분이 검색 지연을 가릅니다.
필터 컨텍스트는 관련도 점수 계산을 건너뛰므로 점수가 필요 없는 조건에 맞습니다. 자주 반복되고 세그먼트 크기 같은 자격 조건을 충족한 필터만 노드 쿼리 캐시의 후보가 됩니다(Elastic 쿼리 캐시 문서). 상태값이나 날짜 범위는 bool 쿼리의 filter 절에 둡니다.
다음 검색도 Elasticsearch Console의 HTTP 요청 형식입니다.
GET /products/_search
{
"query": {
"bool": {
"must": [ { "match": { "title": "무선 이어폰" } } ],
"filter": [
{ "term": { "status": "active" } },
{ "range": { "price": { "lte": 100000 } } }
]
}
}
}위 질의에서 텍스트 적합도는 must 절이 계산하고, 상태와 가격 조건은 filter 절이 캐시와 함께 처리합니다. 점수가 필요 없는 조건을 must에 넣으면 매 검색마다 불필요한 계산이 붙으므로 분리해 둡니다.
인덱스 수명 주기 관리(ILM)
로그나 감사 기록 같은 시계열 데이터는 매일 쌓이고 오래 보관해야 합니다. 인덱스 수명 주기 관리(ILM, Index Lifecycle Management)는 데이터의 나이에 따라 하드웨어 등급을 바꿔 비용과 검색 속도를 함께 맞춥니다.
flowchart LR
Hot["Hot 티어<br/>쓰기와 잦은 검색"] --> Warm["Warm 티어<br/>검색 중심, 비용 절감"]
Warm --> Cold["Cold 티어<br/>드문 조회, 장기 보관"]
Cold --> Delete["Delete<br/>보존 기간 종료 후 삭제"]
- Hot: 빠른 디스크에서 쓰기와 잦은 검색을 받습니다
- Warm: 쓰기를 멈추고 검색 위주로 비용이 낮은 노드에 둡니다
- Cold: 드물게 조회하는 장기 보관 구간입니다
- Delete: 보존 기간이 끝나면 자동으로 삭제합니다
수동 이동은 사실상 불가능하므로 노드 속성(예: node.attr.box_type: hot)을 지정하고 ILM 정책으로 자동화합니다. 예를 들어 인덱스가 30GB를 넘거나 생성 후 7일이 지나면 롤오버(Rollover)로 쓰기를 새 Hot 인덱스에 전달합니다. 90일이 지나면 인덱스를 삭제하도록 설정할 수 있습니다. 이 30GB, 7일, 90일은 예시이며 보존 규제와 적재량에 맞춰 정합니다.
운영체제 커널 튜닝
Elasticsearch는 JVM 위에서 돌지만 안정성은 운영체제 커널 설정에도 달려 있습니다. 아래 값은 Elasticsearch 공식 가이드가 프로덕션에서 권고하는 기준입니다.
| 항목 | 흔한 기본값 | 권고값 | 이유 |
|---|---|---|---|
| vm.max_map_count | 배포판별 상이 | 1048576 권장 | Lucene의 mmap 세그먼트 매핑 한도 확보 |
| vm.swappiness | 배포판 기본 | 1 | 힙 페이지가 디스크로 스왑되는 멈춤 방지 |
| ulimit -n | 배포판별 상이 | 65535 이상 | 세그먼트 병합·검색의 파일 핸들 확보 |
Elastic은 스왑을 완전히 끄는 방법을 우선 권장합니다. 환경상 스왑을 유지해야 한다면 vm.swappiness=1이나 메모리 잠금을 검토합니다(Elastic 스왑 문서). 메모리 잠금은 적용 여부를 노드 API로 확인해야 합니다.
# elasticsearch.yml
bootstrap.memory_lock: truevm.swappiness를 0으로 두는 것은 권장하지 않습니다. 리눅스 커널의 OOM 킬러를 자극할 수 있어 1이 안전한 하한입니다.
장애 신호와 점검 항목
운영 상태가 나빠질 때는 아래 신호가 자주 나타납니다. 신호별 점검 항목으로 원인을 확인합니다.
- 매핑 폭증: 동적 매핑으로 필드가 무한히 늘면 클러스터 상태 메타데이터가 비대해집니다
- 과도한 샤드: 샤드와 세그먼트가 많을수록 메타데이터 관리 비용이 커집니다
- 무분별한 집계: 카디널리티가 큰 필드의 집계는 힙을 빠르게 소진합니다
- refresh·replica·ingest 비용: 색인이 느리면 이 세 값을 함께 들여다봅니다
집계나 색인이 갑자기 느려지면 먼저 힙 사용률과 GC 빈도, 세그먼트 수를 확인합니다. 단일 인덱스에 대량 적재와 실시간 검색을 동시에 몰면 둘 다 나빠지므로, 충돌하는 워크로드는 인덱스로 갈라 둡니다.
정리
Elasticsearch 운영에서는 힙, 색인, 검색, 보존을 함께 관리합니다. 힙은 RAM의 절반 이하와 32GB 경계를 지키고 -Xms와 -Xmx를 고정합니다. 대량 색인 중에는 refresh 주기와 복제본 수를 조절해 쓰기 부하를 줄입니다.
검색에서는 점수가 필요 없는 조건을 filter 절에 넣어 비트셋 캐시를 사용합니다. 시계열 데이터는 ILM으로 Hot부터 Delete까지 자동 관리합니다.
여기 적은 50% 룰, 32GB, 권고 커널값은 Elasticsearch 공식 가이드 기준입니다. 30GB·7일·90일 같은 롤오버 수치는 예시이므로 각자의 적재량과 보존 규제에 맞춰 조정하면 됩니다.