[OpenSearch Deep Dive] 1편: 분산 클러스터 아키텍처와 샤딩(Sharding)의 비밀

[OpenSearch Deep Dive] 1편: 분산 클러스터 아키텍처와 샤딩(Sharding)의 비밀

대규모 로그 플랫폼이나 실시간 검색 시스템을 구축할 때 가장 먼저 맞닥뜨리는 거대한 벽은 "수십억 건의 데이터를 어떻게 분산 저장하고, 장애 상황에서도 중단 없이 검색해낼 것인가"입니다. 오픈소스 분산 검색 엔진의 강자인 오픈서치(OpenSearch)는 이 문제를 정교한 분산 클러스터 아키텍처와 샤딩(Sharding) 메커니즘을 통해 해결합니다.

단순히 데이터를 넣고 찾는 것을 넘어, 오픈서치가 내부적으로 노드의 역할을 어떻게 나누고 데이터를 분배하는지 그 물리적, 논리적 뼈대를 살펴보겠습니다.


1. 역할 분담의 미학: 분산 클러스터 노드 아키텍처

오픈서치 클러스터는 여러 대의 서버(노드)가 모여 하나의 시스템처럼 동작합니다. 이때 모든 노드가 동일한 일을 하는 것이 아니라, 시스템의 안정성과 효율성을 위해 역할을 철저하게 분담합니다. 서비스 규모가 커질수록 이 노드들을 전용(Dedicated) 노드로 분리하는 것이 아키텍처 최적화의 기본입니다.

출처: https://docs.opensearch.org/latest/tuning-your-cluster/

① 클러스터 매니저 노드 (Cluster Manager Node)

과거 Elasticsearch 시절 '마스터(Master) 노드'로 불리던 역할의 발전형입니다. 클러스터 전체의 지휘관 역할을 수행합니다.

  • 핵심 책무: 인덱스의 생성 및 삭제, 어떤 샤드를 어떤 데이터 노드에 배치할지 결정하는 구조 관리, 노드들의 참가/이탈 상태를 관리하는 클러스터 상태(Cluster State) 동기화.
  • 아키텍처 포인트: 데이터의 실제 검색이나 인덱싱 연산에는 관여하지 않기 때문에 CPU나 메모리 부하가 크지 않지만, 이 노드가 죽으면 클러스터 전체가 마비됩니다. 따라서 홀수 개(보통 3개)로 구성하여 고가용성(HA)을 확보하고 분산 시스템의 고질적 문제인 스플릿 브레인(Split-brain)을 방지합니다.

② 데이터 노드 (Data Node)

클러스터의 실질적인 일꾼입니다. 사용자가 저장한 문서(Document)를 실제로 디스크에 보유하고 검색 연산을 수행합니다.

  • 핵심 책무: 데이터의 인덱싱(저장), 데이터 가공, 텍스트 검색 및 집계(Aggregation) 연산 처리.
  • 아키텍처 포인트: CPU, 메모리, 디스크 I/O 자원을 가장 많이 소모하는 노드입니다. 나중에 따로 다루겠지만.. 데이터의 성격(최신 로그 vs 과거 로그)에 따라 Hot-Warm-Cold 구조로 티어링(Tiering)하여 인프라 비용을 최적화하는 핵심 대상이 됩니다.

③ 코디네이팅 노드 (Coordinating Node)

사용자의 요청을 가장 먼저 맞이하는 배달원(혹은 라우터) 역할을 합니다. 모든 노드는 기본적으로 코디네이팅 역할을 할 수 있지만, 대규모 인프라에서는 전용(Dedicated) 코디네이팅 노드를 두는 것을 추천합니다.

  • 핵심 책무: 다음과 같은 순서의 프로세스 처리
    • 사용자 요청 수신
    • 요청을 분석하여 데이터가 분산되어 있는 여러 데이터 노드로 쿼리 분산(Scatter)
    • 각 데이터 노드가 보내온 부분 결과 수집 및 병합(Gather)
    • 최종 결과를 사용자에게 반환.
  • 아키텍처 포인트: 데이터를 보관하지 않으므로 디스크 오버헤드는 없지만, 수많은 노드의 검색 결과를 메모리 위에서 병합하고 정렬해야 하므로 높은 사양의 메모리(RAM)와 네트워크 대역폭이 요구됩니다.

2. 데이터를 쪼개고 분배하는 '샤딩(Sharding)'의 수학적 원리

단일 디스크에 수십 TB의 로그를 다 담을 수는 없습니다. 오픈서치는 하나의 인덱스를 여러 개의 작은 물리적 단위인 샤드(Shard)로 쪼개어 여러 데이터 노드에 골고루 분산시킵니다.

그렇다면 우리가 _id: "log_9921"인 문서를 저장할 때, 오픈서치는 이 문서가 몇 번 샤드로 들어가야 하는지 어떻게 알 수 있을까요? 내부에 명확한 수학적 라우팅 공식이 존재합니다.

$$\text{shard} = \text{hash}(\text{\_id}) \bmod \text{number\_of\_primary\_shards}$$

  1. 유입된 문서의 고유 ID(_id) 값을 해시 함수(MurmurHash3)를 통해 고유한 정수로 변환합니다.
  2. 이 값을 테이블 생성 시 정의한 프라이머리 샤드의 총 개수(Primary Shards)로 나머지 연산(%)을 수행합니다.
  3. 연산 결과로 나온 인덱스 번호의 샤드로 문서가 정확하게 라우팅됩니다.

⚠️ 아키텍처적 제약: Primary Shard 개수 변경 불가

이 수학적 공식 때문에 아주 중요한 아키텍처적 제약이 발생합니다. 인덱스를 이미 생성한 후 운영 중에 프라이머리 샤드의 개수를 바꿔버리면 어떻게 될까요? 분모(나머지 연산의 기준 값)가 바뀌기 때문에 기존에 저장했던 문서들을 찾을 때 완전히 엉뚱한 샤드를 뒤지게 됩니다.

따라서 프라이머리 샤드의 수는 인덱스 생성 시점에 고정되며 변경할 수 없습니다. (개수를 바꾸려면 새 인덱스를 만들어 데이터를 완전히 다시 밀어 넣는 Reindex를 해야 합니다). 반면, 백업본인 레플리카 샤드(Replica Shard)의 개수는 운영 중에도 자유롭게 동적으로 조절할 수 있습니다.

💡
샤드 크기 산정의 기술 (Shard Sizing)
샤드 하나가 너무 크면(예: 100GB 이상) 장애 복구 시 네트워크 바틀넥이 오고, 반대로 너무 잘게 쪼개면(Oversharding) 인덱스 메타데이터가 힙 메모리를 독점합니다.
일반적인 로그 분석 환경에서는 샤드 하나의 크기를 30GB ~ 50GB 내외로 유지하는 것이 업계 베스트 프랙티스입니다.

3. 분산 시스템의 심장: 복제(Replication) 메커니즘의 진화

분산 데이터베이스에서 특정 노드가 갑자기 다운되더라도 데이터 유실 없이 서비스를 지속하는 것은 핵심 과제입니다. 오픈서치는 데이터를 원본인 프라이머리 샤드(Primary Shard)와 복사본인 레플리카 샤드(Replica Shard)로 이중화합니다.

특히 최근 오픈서치는 성능의 한계를 돌파하기 위해 이 복제 아키텍처를 크게 진화시켰습니다.

① 전통적인 문서 레벨 복제 (Document Replication)

과거부터 사용되던 전통적인 방식입니다. 사용자가 데이터를 쓰면 코디네이팅 노드가 프라이머리 샤드로 문서를 보냅니다. 프라이머리가 로컬에 저장을 완료하면, 다시 레플리카 샤드가 있는 노드로 문서를 전달합니다.

  • 문제점: 레플리카 노드 역시 프라이머리와 똑같이 CPU 자원을 소모하며 형태소 분석(Tokenizing)과 인덱싱 연산을 처음부터 반복해야 합니다. 동일한 CPU 연산 낭비가 클러스터 전체에서 중복으로 발생하는 구조입니다.
출처: https://opensearch.org/blog/segment-replication/

② 혁신: 오픈서치 2.x+ 세그먼트 레벨 복제 (Segment Replication)

이 문제를 해결하기 위해 도입된 최신 아키텍처입니다. 이제 레플리카 노드는 문서를 받아서 인덱싱 연산을 수행하지 않습니다.

프라이머리 샤드가 연산을 모두 끝내고 디스크에 쓴 최종 결과물인 '루씬 세그먼트(Lucene Segment) 물리 파일'을 레플리카 노드가 그대로 네트워크로 복사(Copy)해 오기만 합니다.

  • 효과: 일꾼(Data Node)들의 CPU 사용량을 획기적으로 낮출 수 있어, 대규모 로그 인입 환경에서 클러스터 전체 인덱싱 성능이 최대 40~50% 가까이 향상되는 최적화를 이뤄냈습니다.
출처: https://opensearch.org/blog/segment-replication/

③ 클라우드 네이티브로의 확장: 원격 저장소 (Remote Store)

세그먼트 복제 아키텍처는 한 단계 더 나아가 원격 저장소(Remote Store) 개념으로 확장됩니다. 노드 간에 파일을 직접 복사하는 대신 AWS S3와 같은 내구도 높은 오브젝트 스토리지에 프라이머리가 세그먼트를 올리면, 레플리카들은 S3에서 데이터를 다운로드하여 동기화합니다. 노드가 통째로 날아가도 공유 스토리지에서 즉시 복구할 수 있어 고가용성과 비용 절감을 동시에 달성하는 최신 인프라 트렌드입니다.


요약

오픈서치의 압도적인 스케일아웃 능력은 Cluster Manager와 Data Node의 명확한 역할 분담, 해시 라우팅 기반의 균등한 샤드 분산, 그리고 CPU 부하를 극적으로 줄인 세그먼트 레벨 복제 기술의 정교한 조합으로 완성됩니다.

클러스터 단위에서 데이터가 분산되는 큰 그림을 이해했으니, 다음에는 데이터 노드 내부로 눈을 돌려 보겠습니다. 텍스트를 빠르게 찾아내는 검색의 심장 루씬 세그먼트의 내부 구조와 역색인(Inverted Index)의 원리, 그리고 데이터 안정성을 책임지는 Refresh와 Flush 메커니즘을 딥하게 파헤쳐 보겠습니다.