
클러스터의 자원 상황, 요청 빈도, 처리 상태 등의 지표를 수집하고 모니터링하는 것은 ElasticSearch를 운영하는데 필수 업무 중 하나이다. 이번 포스팅에서는 지표를 수집하고 해석하는 방법을 다룰 것이다.
📗 ElasticSearch 상태 확인하기
cat API를 통한 클러스터, 노드, 샤드의 상태 등 다양한 정보를 확인할 수 있다.
[ 클러스터의 상태와 정보 ]
_cat/health API
[
{
"epoch": "1735564800",
"timestamp": "12:00:00",
"cluster": "es-prod-cluster",
"status": "green",
"node.total": "3",
"node.data": "3",
"shards": "12",
"pri": "6",
"relo": "0",
"init": "0",
"unassign": "0",
"pending_tasks": "0",
"max_task_wait_time": "-",
"active_shards_percent": "100.0%"
}
]
| 필드명 | 설명 |
| status* | 클러스터 상태 - green: 모든 샤드가 정상 동작 - yellow: 일부 혹은 모든 레플리캬 샤드가 정상적으로 동작하지 않음 - red: 일부 혹은 모든 프라이머리/레플리카 샤드가 정상적으로 동작하지 않음 |
| node.total | 전체 노드 수 |
| node.data | 전체 데이터 노드 수 |
| shards* | 전체 샤드 수 (primary + replica) 너무 많은 샤드가 있다면 성능 저하를 초래 |
| pri* | primary 샤드 수 |
| relo* | 재배치 중인 샤드 (이 값이 0이 아니라면 샤드들이 재배치되고 있다는 의미) 재배치가 지나치게 많을 경우, 인덱싱 성능이나 검색 성능이 떨어질 수 있으니 반드시 원인을 파악해야 한다. |
| init* | 초기화 중인 샤드 (이 값이 0이 아니라면 샤드들이 초기화되고 있다는 의미) |
| unassign | 할당되지 않은 샤드 샤드가 어느 노드에도 배치되지 않은 상태로 안정성에 문제가 발생할 수 있다. |
| pending_tasks | 대기 중인 클러스터 작업 클러스터가 부하 상황이거나 특정 노드가 서비스 불능 상태일 가능성이 있다. |
| active_shards_percent | 활성 샤드 비율 |
[ 노드의 상태와 정보 ]
_cat/nodes API
ip heap.percent ram.percent cpu load_1m load_5m load_15m node.role master name
192.168.1.10 42 78 15 0.32 0.40 0.45 dim * es-node-1
192.168.1.11 35 74 10 0.28 0.35 0.38 dim - es-node-2
192.168.1.12 30 70 8 0.20 0.25 0.30 dim - es-node-3
| 필드명 | 설명 |
| ip | 노드 IP |
| heap.percent | JVM 힙 사용률 (%) - 만약 이 값이 낮아지지 않고 85% 이상을 계속 유지한다면 OOM이 발생할 가능성이 크기 때문에 원인을 파악해야 한다. |
| ram.percent | 시스템 메모리 사용률 (%) - 노드가 사용할 수 있는 전체 메모리에서 사용 중인 메모리의 사용률이다. OS에서 I/O 부하를 줄이기 위한 페이지 캐시로 사용하기 때문에 수치가 높다. |
| cpu | CPU 사용률 |
| load_1m | 최근 1분 load average |
| node.role | 노드 역할 - d: 데이터 노드 - m: 마스터 노드 - i: 인제스트 노드 ex) mi: 마스터 + 인제스트 노드 |
| master | * = 현재 master |
| name | 노드 이름 |
[ 인덱스의 상태와 정보 ]
_cat/indices API
health status index uuid pri rep docs.count docs.deleted store.size pri.store.size
green open logs-2025.01.01 X1a2B3cD4E5F6G7H8I9 3 1 1254300 1200 8.5gb 4.2gb
green open logs-2025.01.02 J9I8H7G6F5E4D3C2B1A 3 1 1432200 980 9.7gb 4.8gb
yellow open metrics-2025.01 M1N2B3V4C5X6Z7A8S9 1 1 230450 0 1.2gb 1.2gb
red open orders Q9W8E7R6T5Y4U3I2O1 5 1 - - - -
| 필드명 | 설명 |
| health | 인덱스 상태 (green / yellow / red) - 여기서 하나라도 yellow 또는 red면 클러스터의 상태도 동일한 상태가 된다. |
| status | 인덱스 열림 여부 (open / close) - close 상태라면 읽기/쓰기가 불가능하지만, 데이터 노드에서 용량은 차지한다. |
| index | 인덱스 이름 |
| pri | primary 샤드 수 |
| rep | replica 샤드 수 |
| docs.count | 문서 수 |
| docs.deleted | 삭제된 문서 수 |
| store.size | 전체 인덱스 크기 |
| pri.store.size | primary 샤드만의 크기 |
[ 샤드의 상태 확인하기 ]
index shard prirep state docs store ip node
logs-2025.01.01 0 p STARTED 420000 1.4gb 192.168.1.10 es-node-1
logs-2025.01.01 0 r STARTED 420000 1.4gb 192.168.1.11 es-node-2
logs-2025.01.01 1 p STARTED 415000 1.3gb 192.168.1.11 es-node-2
logs-2025.01.01 1 r STARTED 415000 1.3gb 192.168.1.12 es-node-3
logs-2025.01.01 2 p STARTED 419300 1.4gb 192.168.1.12 es-node-3
logs-2025.01.01 2 r STARTED 419300 1.4gb 192.168.1.10 es-node-1
metrics-2025.01 0 p STARTED 230450 1.2gb 192.168.1.10 es-node-1
metrics-2025.01 0 r UNASSIGNED
| 필드명 | 설명 |
| index | 인덱스 이름 |
| shard | 샤드 번호 (0번부터 시작) |
| prirep | p = primary / r = replica |
| state | 샤드 상태 - STARTED: 정상 - INITIALIZING: 초기화하는 상태 혹은 샤드에 문제가 발생하여 새롭게 배치할 때의 상태 - RELOCATING: 샤드가 현재의 노드에서 다른 노드로 이동하고 있는 상태 - UNASSIGNED: 샤드가 배치되지 않은 상태 |
| docs | 문서 수 |
| store | 샤드 크기 |
| ip | 샤드가 올라간 데이터 노드의 ip |
| node | 노드 이름 |
💡 샤드가 배치되지 않은 대표적인 원인
INDEX_CREATED:
인덱스가 생성된 후, 샤드가 배치되지 않았음을 의미하는데, 샤드를 특정 노드에만 배치되도록 강제하거나 특정 노드에 배치되지 않도록 강제했을 때 발생.
NODE_LEFT:
샤드가 배치된 데이터 노드에 문제가 생겨서 클러스터에서 제외될 경우 발생하며 가장 흔한 코드.
📌 클러스터의 상태가 red일 때 _cat/shards API는 매우 중요한 지표
클러스터가 red 상태라면 가장 먼저 _cat/indices를 통해서 어떤 인덱스가 red 상태인지 확인.
이를 통해 문서의 유실이 발생했는지 여부를 확인할 수 있다.
만약, red상태의 인덱스가 현재 색인이 일어나고 있다면 _cat/shards를 통해 어느 정도의 비율로 문서 유실이 발생하는지 알 수 있다.
📘 status API로 성능 지표 확인
| 지표 | 의미 |
| 색인 성능 | 초당 몇 개의 문서를 색인할 수 있는지 |
| 검색 성능 | 초당 몇 개의 쿼리를 처리할 수 있는지 |
| GC 성능 | Stop-The_World가 얼마나 자주, 오래 발생하는지 |
| rejected | 클러스터가 요청을 거절한 횟수 |
[ 색인 성능 ]
_status/indexing API의 색인 성능만 수집
{
"_all": {
"indexing": {
"index_total": 152340,
"index_time_in_millis": 9876,
"index_current": 12,
....
}
}
}
| 필드명 | 설명 |
| index_total | 전체 인덱스된 문서 수 (누적) |
| index_time_in_millis | 색인에 소요된 총 시간 |
| index_current | 현재 진행 중인 색인 작업 수 |
index_total은 누적값이기 때문에 특정 시간을 기준으로 조회한 결과와 비교해서 색인 성능을 확인할 수 있다.
📃 예시1) 초당 색인한 문서 수
10초 전 index_total = 150,000
현재 index_total = 152,340
2,340 docs / 10s
= 234 docs/sec
📃 예시2) 문서 하나당 색인하는데 걸리는 시간
10초 전 index_time_in_millis = 3,500
현재 index_time_in_millis = 9,876
10초동안 색인하는 데에 6376ms 소요
2,340docs / 6,376ms
= 0.36ms
즉, 이 클러스터의 프라이머리 샤드는 초당 234개의 문서를 색인할 수 있고, 문서 하나당 색인 성능은 0.36ms가 된다.
검색 성능도 이와 유사하게 확인할 수 있다. 다만, 검색은 query + fetch 과정이 일어나기 때문에 두 과정에 대한 지표를 토대로 성능을 계산해야 한다.
[ rejected 살펴보기 ]
rejected는 ElasticSearch 클러스터 레벨에서 현재 처리량이 부족하다는 것을 알 수 있는 지표 중 하나이다. 현재 처리할 수 있는 양보다 많은 요청이 들어오면 큐에 쌓아 놓는다. 하지만, 큐도 가득찬 경우, rejected 에러를 발생시키며 요청을 처리하지 못한다.
nodes/status API를 통해 확인할 수 있고 스레드별로 rejected 지표를 확인할 수 있다.
{
"nodes": {
"node-1": {
"thread_pool": {
"search": {
"threads": 13,
"queue": 1000,
"active": 13,
"rejected": 245
},
"write": {
"threads": 8,
"queue": 200,
"active": 8,
"rejected": 1021
},
"bulk": {
"threads": 4,
"queue": 200,
"active": 4,
"rejected": 356
}
}
}
}
}
| 스레드명 | 설명 |
| search | 동시 검색 과다, slow query |
| write | refresh 과다, 디스크 병목 |
| bulk | bulk 사이즈 과대, ingest 병목 |
❓ rejected가 발생하는 원인
초기에 구성한 클러스터의 처리량이 부족한 경우
> 데이터 노드를 증설하는 것 외에는 특별한 방법이 없다.
요청이 순간적으로 늘어나서 순간 요청을 처리하지 못하는 경우:
> 큐를 늘리는게 도움이 될 수 있다.
📚 정리
클러스터/노드 등의 상태를 확인하면서 ElasticSearch 운영 업무에 필요한 API들을 알 수 있었다.
각 지표들을 통해 문제의 원인을 파악해나가는 것이 해당 챕터의 핵심으로 보였고 본문에는 작성하지 않았지만, 힙 메모리와 관련된 GC 성능에서도 Stop-The-World 혹은 OOM이 발생하지 않도록 모니터링하는 것이 중요하다는 것을 알았다.
'Developer's_til > 그외 개발 공부' 카테고리의 다른 글
| [ELK] ElasticSearch 정의와 기본 개념 (0) | 2025.12.29 |
|---|---|
| [리액트] 렌더링되는 과정과 예시 (0) | 2025.10.19 |
| [Java] Json을 활용하는 구글의 오픈소스 Gson (1) | 2022.01.05 |
| [Java] Optional이란? 개념과 사용법 - 1 (2) | 2022.01.03 |
| [Design Pattern] 컴포지트 패턴(Composite Pattern)이란 (0) | 2021.12.31 |