2장. 클러스터 아키텍처 — 노드들은 어떻게 한 팀이 되는가
마스터는 지휘하고, 데이터 노드는 일하고, coordinating 노드는 교통정리를 합니다. 이후 모든 트러블슈팅과 용량 산정은 이 장의 모델 위에서 이루어집니다.
① 노드 역할(master/data/coordinating 등)의 분리 ② cluster state — 클러스터의 단일 진실 ③ 마스터 선출과 쿼럼(왜 3대인가) ④ 검색·색인 요청이 coordinating 노드에서 샤드로 fan-out되는 흐름
2.1 노드 역할 — 한 노드는 하나의 프로세스가 아니라 "역할의 집합"
Elasticsearch 노드는 node.roles 설정으로 결정되는 하나 이상의 역할을 갖습니다. 소규모에서는 한 노드가 모든 역할을 겸하지만, 규모가 커지면 역할을 분리하는 것이 운영의 기본입니다.
| 역할 | 약어 | 하는 일 |
|---|---|---|
master | m | 클러스터 상태 관리, 인덱스 생성/삭제, 샤드 할당 결정 |
voting_only | v | 마스터 선출 투표만 참여, 자신은 마스터가 되지 않음 |
data_content | s | 검색 중심의 일반(비시계열) 데이터 |
data_hot | h | 최근 시계열 데이터 — 빈번한 색인/검색, SSD |
data_warm | w | 색인이 끝난 데이터, 가끔 검색 |
data_cold | c | 거의 검색 안 되는 오래된 데이터, searchable snapshot |
data_frozen | f | 스냅샷 저장소 부분 마운트 — 매우 저렴, 매우 느림 |
ingest | i | ingest pipeline 실행 (문서 전처리) |
ml / transform | l / t | Machine Learning / Transform 작업 |
| (역할 없음) | - | coordinating-only — 요청 라우팅과 결과 머지만 담당 |
# elasticsearch.yml — 역할별 노드 설정 예
# 마스터 전용 노드: 데이터/검색 부하로부터 격리
node.roles: [ master ]
# hot 데이터 노드: 최신 데이터 색인 + 검색 + 전처리
node.roles: [ data_hot, data_content, ingest ]
# coordinating-only 노드: 역할을 전부 비운다
node.roles: [ ]
시계열 데이터(로그·메트릭)는 Hot → Warm → Cold → Frozen 순으로 값싼 하드웨어로 이동시키는 것이 표준 패턴입니다. 데이터가 오래될수록 검색 빈도가 급감하기 때문에, 비용/성능 곡선을 따라 내려보내는 것이죠. 이 이동은 ILM(Index Lifecycle Management)이 자동화합니다.
마스터 쿼럼은 홀수가 권장되지만 전용 마스터 3대는 비용이 듭니다. 전용 마스터 2대 + voting_only 1대(보통 데이터 노드 겸직)로 쿼럼 3을 유지하며 비용을 줄일 수 있습니다. 단, 공식 문서는 운영 환경에서는 진짜 전용 마스터 3대를 권장합니다.
2.2 Cluster State — 클러스터의 단일 진실
Cluster state는 클러스터의 모든 메타데이터를 담은 하나의 자료구조입니다. 인덱스 설정과 매핑, 샤드가 어느 노드에 있는지, 노드 목록과 역할, ILM 정책까지 전부 여기 들어 있습니다. 그리고 이 정보의 단일 진실 공급자(single source of truth)는 마스터 노드입니다.
인덱스 생성 같은 클러스터 변경 요청은 최종적으로 마스터 노드에서 처리됩니다. 현재 모든 노드는 state v41을 들고 있습니다.
마스터가 변경을 반영한 새 cluster state(v42)를 만듭니다. 버전 번호가 붙어 있어 어느 것이 최신인지 항상 판별할 수 있습니다.
마스터가 새 state를 모든 노드에 publish합니다. 노드 수와 state 크기에 비례해 네트워크 비용이 듭니다.
모든 노드가 v42로 갱신 완료. 각 노드는 새 state를 보고 자기가 할 일(예: 새로 할당된 샤드 시작)을 실행합니다. 이 publish가 느려지면 클러스터 전체가 느려집니다 — oversharding이 위험한 이유입니다(4장).
인덱스가 수천 개, 샤드가 수만 개가 되면 state가 수백 MB로 커지고, 변경 때마다 이 큰 덩어리의 publish가 일어나 마스터가 ack를 기다리며 클러스터가 멈칫거리게 됩니다. GET _cluster/state?filter_path=metadata 응답 크기가 100MB를 넘으면 oversharding을 의심하세요.
2.3 Discovery — 노드들이 서로를 찾는 법
노드는 마법처럼 서로를 찾지 않습니다. 각 노드는 마스터 후보 노드의 주소 목록을 알고 시작해야 합니다. 7.0부터 도입된 새 Discovery 체계의 핵심 설정은 두 가지입니다.
# elasticsearch.yml
# (1) 같은 cluster.name을 가진 노드만 합류할 수 있다
cluster.name: prod-logs
# (2) seed_hosts — 처음 접속해 볼 마스터 후보들의 주소 (상시 유지)
discovery.seed_hosts:
- master-1.es.internal
- master-2.es.internal
- master-3.es.internal
# (3) initial_master_nodes — "최초 부트스트랩" 한 번만 사용!
# 클러스터가 형성된 후에는 모든 노드의 yaml에서 제거할 것
cluster.initial_master_nodes:
- master-1
- master-2
- master-3
cluster.initial_master_nodes는 빈 클러스터를 처음 띄울 때 한 번만 의미가 있습니다. 새 노드를 추가하며 기존 yaml을 그대로 복사하면, 새 노드가 기존 클러스터를 무시하고 별도 클러스터로 부트스트랩해버릴 수 있습니다 — split-brain의 지름길입니다. 클러스터 형성 직후 모든 노드의 yaml에서 이 설정을 제거하세요.
2.4 마스터 선출 — 왜 하필 3대인가
마스터 선출은 Raft에서 영감을 받은 합의 프로토콜로 동작합니다. 선출에 투표하는 마스터 후보들의 집합을 voting configuration이라 하고, 이 집합의 과반수(strict majority)가 동의해야 마스터가 정해집니다. 과반수 규칙이 있어야 네트워크가 반으로 갈라져도 두 쪽이 동시에 마스터를 뽑는 사태(split-brain)를 막을 수 있습니다.
마스터 후보 3대의 클러스터입니다. voting configuration은 3개 노드, 과반수 quorum은 floor(3/2)+1 = 2입니다. 현재 마스터는 master-1.
master-1이 갑자기 다운됩니다. 하드웨어 장애, 긴 GC pause, 네트워크 단절 — 원인은 다양합니다.
남은 후보 master-2와 master-3이 선출을 시작합니다. 2표는 3의 과반수이므로 선출이 성립합니다.
master-2가 새 마스터로 승격되고 클러스터는 정상 운영을 계속합니다. 장애 감지부터 재선출까지 보통 수 초입니다.
만약 후보가 2대였다면? quorum이 2인데 1대가 죽으면 1표뿐 — 선출 불가로 클러스터가 멈춥니다. 그래서 마스터 후보는 3대(또는 5대)여야 합니다.
| 마스터 후보 수 | quorum | 견딜 수 있는 장애 | 평가 |
|---|---|---|---|
| 1 | 1 | 0대 | SPOF — 단일 장애점 |
| 2 | 2 | 0대 | ❌ 1대만 죽어도 쿼럼 미달 |
| 3 | 2 | 1대 | ✅ 표준 권장 |
| 4 | 3 | 1대 | 3보다 나을 게 없는데 비용만 증가 |
| 5 | 3 | 2대 | 대규모 클러스터용 |
7.x 이후 voting configuration은 노드가 추가/제거될 때 자동으로 조정됩니다. 다만 장애 상황에서 stale하게 남으면 POST _cluster/voting_config_exclusions로 수동 개입이 필요할 수 있습니다.
2.5 요청 라우팅 — coordinating 노드에서 샤드로 fan-out
클라이언트 요청은 어느 노드로 보내도 됩니다. 요청을 받은 노드가 그 순간 coordinating node가 되어 교통정리를 맡습니다. 검색은 Query then Fetch라는 2단계로 처리됩니다.
클라이언트가 아무 노드(Node-X)에나 검색 요청을 보냅니다. 요청을 받은 노드가 coordinating node 역할을 맡습니다.
Node-X는 cluster state에서 대상 인덱스의 샤드가 어디 있는지 찾습니다. 각 샤드에 대해 primary/replica 중 하나를 부하 분산으로 고릅니다.
Query Phase: 질의를 모든 관련 샤드로 fan-out합니다. 각 샤드는 독립적으로 검색을 수행합니다.
각 샤드는 문서 전체가 아니라 top-K개의 문서 ID + 점수만 반환하고, coordinating이 이를 머지해 글로벌 top-K를 정합니다.
Fetch Phase: 최종 선택된 문서들의 실제 내용(_source)만 해당 샤드에서 가져옵니다. 탈락한 문서의 본문은 네트워크를 타지 않습니다.
완성된 결과가 클라이언트로 돌아갑니다. 이 구조 때문에 from=10000 같은 deep pagination은 모든 샤드가 from+size개를 반환해야 해서 매우 비쌉니다 → search_after 권장.
색인(쓰기) 요청은 경로가 다릅니다. coordinating 노드가 hash(_id) % 샤드 수로 단 하나의 primary 샤드를 찾아 전달하고, primary가 색인 후 모든 in-sync replica에 동기 복제합니다. 모든 사본의 ack를 받은 뒤에야 클라이언트에 응답하므로, 색인 응답 시점에 데이터는 모든 활성 사본에 도달해 있습니다 (4장에서 상세히).
2.6 운영 팁 — 클러스터 토폴로지 설계
- 전용 마스터 3대는 규모와 무관한 표준입니다. 데이터 노드의 GC pause나 디스크 I/O 폭증이 마스터 선출 타임아웃을 유발하면 클러스터 전체가 멈춥니다. 마스터 노드는 heap 4~8GB의 작은 사양이면 충분합니다.
- coordinating-only 노드는 대부분 불필요합니다. 거대한 집계 쿼리가 잦거나, 클라이언트 연결이 수천 개이거나, 검색/색인 트래픽 격리가 필요할 때만 검토하세요.
- 마스터 노드의 디스크도 모니터링하세요. cluster state를 디스크에 persist하므로, 디스크가 차면 선출이 실패합니다.
# 클러스터 토폴로지 상시 확인 — 운영자의 3종 세트
GET /_cluster/health
# 노드별 역할/heap/디스크 (master 칼럼의 *가 현재 마스터)
GET /_cat/nodes?v=true&h=name,node.role,heap.percent,disk.used_percent,master
# 지금 마스터는 누구인가
GET /_cat/master?v=true
✍️ 이해도 체크
from=10000)은 모든 샤드가 from+size개를 반환해야 해서 매우 비싸집니다.이 장의 원문 문서: chapters/ch02_cluster_architecture.md — data tier별 샤드 한도, forced awareness, 클러스터 구성 예시 다이어그램 등이 담겨 있습니다.