Elasticsearch 샤드 크기 조정 전략: 최적의 균형 찾기
강력한 분산 검색 및 분석 엔진인 Elasticsearch는 기본 아키텍처, 특히 샤드 개념 덕분에 확장성과 성능을 크게 향상시킬 수 있습니다. 샤드는 본질적으로 데이터의 하위 집합을 저장하는 독립적인 Lucene 인덱스입니다. 샤드의 크기를 이해하고 최적화하는 것은 단순히 모범 사례를 넘어 클러스터의 성능, 안정성 및 비용 효율성에 직접적인 영향을 미치는 중요한 요소입니다.
이 글에서는 Elasticsearch 샤드 크기 조정의 복잡성에 대해 안내해 드릴 것입니다. 샤드 크기 조정이 왜 그렇게 중요한지, 최적의 크기에 영향을 미치는 다양한 요소, 그리고 너무 많거나 너무 적은 샤드를 가질 때의 장단점을 살펴보겠습니다. 이 글을 마칠 때쯤에는 특정 사용 사례에 적합한 샤드 구성을 결정하고 일반적인 함정을 피하며 균형 잡히고 성능이 뛰어나며 확장 가능한 Elasticsearch 클러스터를 구축하는 데 도움이 되는 실용적인 전략과 실행 가능한 통찰력을 얻게 될 것입니다.
Elasticsearch 샤드 이해하기
크기 조정에 대해 자세히 알아보기 전에, 샤드가 무엇이며 Elasticsearch 클러스터 내에서 어떻게 작동하는지 간략하게 살펴보겠습니다.
샤드란 무엇인가요?
Elasticsearch에서 인덱스는 데이터의 논리적 그룹입니다. 이 데이터를 분산하고 병렬 처리를 가능하게 하기 위해 인덱스는 하나 이상의 _샤드_로 분할됩니다. 각 샤드는 자체 포함된 Lucene 인덱스입니다. 인덱스를 생성할 때 해당 인덱스가 가질 프라이머리 샤드의 수를 정의합니다.
고가용성 및 읽기 확장성을 위해 Elasticsearch는 레플리카 샤드를 지정할 수도 있도록 합니다. 레플리카 샤드는 프라이머리 샤드의 정확한 복사본입니다. 프라이머리 샤드가 있는 노드가 실패하면 레플리카가 승격되어 그 자리를 차지하여 데이터 가용성을 보장하고 데이터 손실을 방지합니다. 레플리카는 또한 검색 요청을 처리하여 읽기 로드를 분산합니다.
샤드 작동 방식
문서를 색인할 때 Elasticsearch는 라우팅 알고리즘(기본적으로 문서 ID 기반)에 따라 해당 문서가 속할 프라이머리 샤드를 결정합니다. 이 문서는 해당 특정 프라이머리 샤드 및 해당 레플리카 샤드에 저장됩니다. 검색할 때 요청은 모든 관련 샤드로 전송되며, 각 샤드는 데이터의 해당 부분을 병렬로 처리합니다. 그 후 결과가 집계되어 클라이언트에게 반환됩니다. 이러한 병렬 처리가 Elasticsearch에 엄청난 속도와 확장성을 부여하는 요소입니다.
샤드 크기 조정이 중요한 이유
최적의 샤드 크기 조정은 건전한 Elasticsearch 클러스터를 위한 기본적인 요소입니다. 잘못된 크기 조정은 느린 쿼리 성능부터 값비싼 리소스 낭비, 불안정한 복구 시나리오에 이르기까지 수많은 문제로 이어질 수 있습니다.
성능
- 쿼리 속도: 적절하게 크기가 조정된 샤드는 쿼리를 효율적으로 처리할 수 있습니다. 너무 작은 샤드는 더 많은 조정 오버헤드를 의미하고, 너무 큰 샤드는 개별 샤드 검색 시간을 길게 만듭니다.
- 색인 처리량: 마찬가지로 색인 성능에도 영향을 미칠 수 있습니다. 샤드가 너무 작으면 많은 샤드를 관리하는 오버헤드로 인해 쓰기 속도가 느려질 수 있습니다. 샤드가 너무 크면 개별 샤드 성능이 병목 현상을 일으킬 수 있습니다.
리소스 활용
각 샤드는 CPU, 메모리(JVM 힙), 디스크 I/O를 포함하여 자신이 상주하는 노드에서 리소스를 소비합니다. 적절한 크기 조정은 노드가 과부하되거나 과소 활용되지 않고 효율적으로 사용되도록 보장합니다.
확장성
샤드는 Elasticsearch의 분산 단위입니다. 수평적으로 확장하려면 더 많은 노드를 추가해야 하며, Elasticsearch는 샤드를 노드 전체에 재분배합니다. 샤드가 너무 크면 재분배하는 데 더 오랜 시간이 걸리고 더 많은 네트워크 대역폭이 필요합니다. 샤드가 너무 적으면 프라이머리 샤드 수 이상으로 워크로드를 분산할 수 없으므로 조기에 확장 한계에 도달할 수 있습니다.
복구 및 안정성
- 노드 장애: 노드가 실패하면 Elasticsearch는 프라이머리 샤드를 재할당(레플리카 승격)하고 손실된 레플리카를 재생성해야 합니다. 이 작업에 걸리는 시간은 관련된 샤드의 크기와 수에 직접 비례합니다.
- 클러스터 복구: 큰 샤드는 복구하고 복제하는 데 더 오랜 시간이 걸리므로 노드 장애 또는 클러스터 재시작 시 취약성 기간이 길어집니다.
샤드 크기 조정에 영향을 미치는 요소
올바른 샤드 크기를 결정하는 것은 모든 상황에 적용되는 단일 해결책이 아닙니다. 이는 특정 사용 사례 및 인프라에 특정한 여러 상호 의존적인 요소에 따라 달라집니다.
- 데이터 볼륨 및 성장: 현재 데이터 크기와 예상 성장률은 기본입니다. 정적인 100GB 인덱스는 매일 1TB씩 증가하는 롤링 인덱스와는 다른 요구 사항을 가질 것입니다.
- 문서 크기 및 스키마 복잡성: 많은 필드나 매우 큰 문서를 가진 인덱스는 각 문서 처리에 더 많은 리소스가 필요하므로 더 작은 샤드에서 이점을 얻을 수 있습니다.
- 쿼리 패턴:
- 검색 중심: 클러스터가 주로 검색에 사용되는 경우, 병렬화를 극대화하고 개별 샤드 검색 시간을 최소화하기 위해 더 많은 수의 작은 샤드를 우선시할 수 있습니다.
- 분석 중심(집계): 대규모 집계는 더 큰 샤드에서 더 잘 수행될 수 있습니다. 이는 많은 작은 샤드에서 결과를 결합하는 오버헤드가 상당해질 수 있기 때문입니다.
- 색인 속도: 높은 색인 속도는 쓰기 로드를 분산하기 위해 더 많은 샤드에서 이점을 얻을 수 있지만, 너무 많은 샤드는 오버헤드를 유발할 수 있습니다.
- 노드 사양: 데이터 노드의 CPU, RAM(JVM 힙 크기) 및 디스크 유형(SSD vs. HDD)은 매우 중요합니다. 더 강력한 노드는 더 많은 샤드 또는 더 큰 샤드를 처리할 수 있습니다.
- 클러스터 토폴로지: 샤드를 분산할 수 있는 데이터 노드의 총 수는 실행 가능한 샤드 수에 직접적인 영향을 미칩니다.
장단점: 너무 많은 샤드 vs. 너무 적은 샤드
최적의 균형을 찾는 것은 양극단의 결과를 이해하는 것을 의미합니다.
너무 많은 샤드의 결과
더 많은 샤드가 더 많은 병렬화를 제공하는 것처럼 보이지만, 수확 체감의 지점이 있습니다:
- 더 높은 오버헤드: 각 샤드는 메타데이터, 열린 파일, 세그먼트 병합 등을 위해 CPU와 메모리(JVM 힙)를 소비합니다. 한 노드에 너무 많은 샤드가 있으면 샤드 자체를 관리하는 데 더 많은 전체 리소스가 소비되어 실제 데이터 처리에는 더 적은 리소스가 남게 됩니다.
- 팁: 일반적인 경험 법칙은 샤드당 1MB를 초과하는 힙을 허용하지 않는 것입니다. 30GB 힙의 경우, 레플리카를 포함하여 모든 노드에서 총 30,000개의 샤드가 됩니다.
- 느린 복구: 노드 장애 또는 재조정 중에는 많은 작은 샤드를 관리하고 이동하는 데 더 적은 수의 큰 샤드보다 더 많은 시간과 네트워크 I/O가 필요합니다.
- 리소스 경합 증가: 많은 샤드가 동일한 노드에서 활발하게 작업(예: 세그먼트 병합, 쿼리 응답)을 수행할 때, CPU, 메모리 및 디스크 I/O를 놓고 경합하게 되어 전반적인 성능이 저하됩니다.
- "샤드 비대화": 작고 대부분 비어 있는 많은 샤드를 가진 클러스터는 비효율적입니다. 이는 비례하는 데이터 이점 없이 관리를 위한 리소스를 소비합니다.
너무 적은 샤드의 결과
반대로 너무 적은 샤드를 갖는 것도 상당한 문제를 야기합니다:
- 제한된 병렬화: 인덱스에 몇 개의 큰 샤드만 있는 경우, 워크로드를 여러 노드/코어에 분산할 수 없으므로 검색 쿼리가 클러스터의 전체 처리 능력을 활용할 수 없습니다.
- 핫스팟: 단일 노드의 큰 샤드는 불균형하게 많은 읽기 또는 쓰기 요청을 받으면 "핫스팟"이 되어 해당 특정 노드의 리소스 포화를 초래할 수 있습니다.
- 확장 어려움: 예를 들어 인덱스에 5개의 프라이머리 샤드만 있는 경우, 해당 인덱스를 최대 5개의 데이터 노드에만 효과적으로 분산할 수 있습니다. 모든 샤드가 이미 다른 노드에 있는 경우, 더 많은 노드를 추가해도 특정 인덱스의 성능에는 도움이 되지 않습니다.
- 느린 재조정: 재조정 중에 단일의 매우 큰 샤드를 네트워크를 통해 이동하는 것은 시간이 많이 걸리고 I/O 집약적인 작업으로, 클러스터 안정성에 잠재적으로 영향을 미칠 수 있습니다.
- 더 긴 복구 시간: 복구 또는 복사해야 하는 단일의 큰 샤드는 장애 후 클러스터의 복구 시간을 크게 연장할 수 있습니다.
일반 권장 사항 및 모범 사례
단일 규칙이 모든 경우에 적용되는 것은 아니지만, 몇 가지 널리 받아들여지는 지침은 좋은 시작점을 제공합니다.
목표 샤드 크기
개별 샤드 크기(색인 및 잠재적 병합 후)에 대한 가장 일반적으로 인용되는 권장 사항은 10GB에서 50GB 사이입니다. 일부 자료에서는 특정 시나리오(예: 대부분 추가 전용 쓰기와 복잡한 쿼리가 적은 시계열 데이터)의 경우 이를 최대 100GB까지 확장합니다. 이 범위는 일반적으로 관리 용이성, 복구 속도 및 효율적인 리소스 활용 사이의 좋은 균형을 제공합니다.
- 이 범위가 적합한 이유?:
- 복구: 이 범위의 샤드는 노드 장애 후 비교적 빠르게 복구될 수 있습니다.
- 성능: 오버헤드를 최소화할 만큼 충분히 크면서도 효율적인 처리와 빠른 병합을 허용할 만큼 충분히 작습니다.
- 확장성: 노드 전반에 걸쳐 유연한 분산을 가능하게 합니다.
노드당 샤드 수
단일 노드에 과도한 수의 샤드를 두는 것을 피해야 합니다. 일반적인 휴리스틱은 노드에 할당된 JVM 힙 1GB당 총 샤드(프라이머리 + 레플리카) 수를 10-20개 미만으로 유지할 것을 제안합니다. 예를 들어, 30GB 힙을 가진 노드는 이상적으로 300-600개 이하의 샤드를 호스트해야 합니다. 이는 샤드 메타데이터에 대한 과도한 메모리 사용을 방지하고 경합을 줄이는 데 도움이 됩니다.
Hot-Warm-Cold 아키텍처 및 샤드 크기 조정
Hot-Warm-Cold (HWC) 아키텍처에서는 샤드 크기 조정이 다를 수 있습니다:
- 핫 티어: 활성 쓰기를 받고 자주 쿼리되는 데이터 노드입니다. 여기서는 색인 처리량과 쿼리 병렬화를 극대화하기 위해 약간 더 많은 샤드 또는 더 작은 샤드를 선택할 수 있습니다.
- 웜/콜드 티어: 오래되었고 덜 자주 액세스되는 데이터를 보관하는 노드입니다. 이러한 샤드는 색인이 중지되고 병합이 완료되었기 때문에 일반적으로 더 큽니다. 여기서는 총 샤드 수를 줄이고 관련 오버헤드를 줄이기 위해 더 큰 샤드(100GB 이상)가 허용될 수 있으며, 특히 비용 최적화된 스토리지에서 더욱 그렇습니다.
레플리카
항상 레플리카를 사용하세요! 고가용성을 위해 프라이머리 샤드당 최소 1개의 레플리카(총 2개의 데이터 복사본)가 필수적입니다. 레플리카는 또한 검색 요청을 분산하여 읽기 용량을 증가시킵니다. 최적의 레플리카 수는 가용성 요구 사항과 쿼리 로드에 따라 달라집니다.
샤드 크기 결정을 위한 실용적인 전략
다음은 초기 샤드 크기 조정 전략을 도출하고 반복적인 개선 과정을 거치는 단계별 접근 방식입니다.
1단계: 총 데이터 볼륨 및 성장을 추정
인덱스(또는 롤링 일간/월간 인덱스)가 수명 주기 동안 얼마나 많은 데이터를 보유할지 예측하십시오. 평균 문서 크기를 고려하십시오.
- 예시: 하루에 100GB의 데이터를 수집하고 30일 동안 보존할 것으로 예상합니다. 총 활성 데이터는 약 3TB(
100GB/일 * 30일)가 될 것입니다.
2단계: 목표 샤드 크기 결정
프라이머리 샤드당 30GB-50GB라는 일반적인 권장 사항에서 시작하십시오. 사용 사례에 따라 조정하십시오:
- 더 작은 샤드 (예: 10-20GB): 쿼리 처리량이 매우 높거나, 큰 문서에 대한 복잡한 집계가 많거나, 데이터가 매우 자주 변경되는 경우.
-
더 큰 샤드 (예: 50-100GB): 대부분 시계열 데이터, 추가 전용 인덱스 또는 덜 빈번하고 간단한 쿼리를 사용하는 경우.
-
예시 (1단계에서 계속): 평균 프라이머리 샤드 크기를 50GB로 목표로 하겠습니다.
3단계: 초기 프라이머리 샤드 수 계산
총 예상 데이터 볼륨을 목표 샤드 크기로 나눕니다.
프라이머리 샤드 수 = (총 데이터 볼륨) / (목표 샤드 크기)
- 예시:
3000GB / 50GB = 60개의 프라이머리 샤드.
4단계: 노드 리소스 및 힙 크기 고려
클러스터가 GB 힙당 샤드 규칙을 준수하면서 얼마나 많은 프라이머리 및 레플리카 샤드를 편안하게 호스트할 수 있는지 결정하십시오.
- 노드당 힙: 각 데이터 노드에 30GB의 JVM 힙이 있다고 가정해 봅시다.
- 노드당 최대 샤드 수 (대략):
GB 힙당 10-20개 샤드규칙을 사용하면, 30GB 힙 노드는30 * 10 = 300개에서30 * 20 = 600개의 샤드를 호스트할 수 있습니다. - 총 레플리카 수: 1개의 레플리카를 사용하는 경우(강력히 권장),
60개의 프라이머리 샤드 + 60개의 레플리카 샤드 = 총 120개의 샤드를 갖게 됩니다. - 데이터 노드 수: 총 120개의 샤드를 목표로 하고 각 노드가 예를 들어 300개의 샤드를 처리할 수 있다고 가정하면(범위 내의 보수적인 추정치),
120 / (예: 노드당 60개의 샤드)= 최소 2개의 노드에서 이 120개의 샤드를 실행할 수 있습니다. 그러나 탄력성과 분산을 위해, 핫스팟을 방지하고 노드 장애에 대비하여 이러한 샤드와 레플리카를 효과적으로 분산하기 위해 일반적으로 최소 3-5개의 데이터 노드를 사용하는 것이 좋습니다.
예시 시나리오
각각 30GB 힙을 가진 3노드 데이터 클러스터를 가정해 봅시다:
- 총 힙:
3개 노드 * 노드당 30GB = 90GB - 총 최대 샤드 수 (10 샤드/GB 사용):
90GB * 10 = 900개의 샤드 - 현재 계산된 총 샤드 수:
120개의 샤드 (프라이머리 60개 + 레플리카 60개) - 이
총 120개의 샤드는 900개 샤드 제한 내에 있으므로 초기 추정치가 합리적임을 시사합니다. - 노드당 평균 샤드 수:
총 120개의 샤드 / 3개 노드 = 노드당 40개의 샤드. 이는 30GB 힙 노드에 매우 적합한 수치입니다.
5단계: 테스트 및 모니터링
이것은 가장 중요한 단계입니다. 이론적인 계산은 단지 시작점일 뿐입니다.
- 부하 테스트: 예상되는 색인 및 쿼리 패턴을 시뮬레이션하십시오. 성능 지표를 관찰하십시오.
-
모니터링 도구: Kibana의 내장 모니터링, Elasticsearch의
_catAPI 또는 외부 모니터링 도구(예: Prometheus, Grafana)를 사용하여 다음을 주시하십시오:_cat/shards: 샤드 크기 및 분포 확인._cluster/stats: 클러스터 수준 통계, 특히 JVM 힙 사용량.- 개별 노드의 CPU, 메모리 및 디스크 I/O.
- 색인 및 검색 지연 시간.
- 세그먼트 병합 활동.
```bash
샤드 할당 및 크기 정보 가져오기
GET _cat/shards?v=true&h=index,shard,prirep,state,docs,store,node
힙 사용량 및 샤드 수에 대한 클러스터 통계 가져오기
GET _cluster/stats
```
6단계: 반복적 조정
모니터링 결과를 바탕으로 샤드 수를 조정할 준비를 하십시오. 여기에는 다음이 포함될 수 있습니다:
- Shrink API: 더 이상 쓰기가 이루어지지 않는 인덱스에 너무 많은 프라이머리 샤드가 있는 경우,
_shrinkAPI를 사용하여 프라이머리 샤드 수를 줄일 수 있습니다. 이 작업은 닫힌 인덱스와 충분한 공간을 필요로 합니다. - Split API: 인덱스의 샤드가 너무 커져 성능 저하가 발생하는 경우,
_splitAPI를 사용하여 프라이머리 샤드 수를 늘릴 수 있습니다. 이 작업은 열린 인덱스를 필요로 합니다. - Reindex API: 매핑 수정 또는 활성 상태로 쓰기가 이루어지는 인덱스의 샤드 수 변경과 같은 더 복잡한 변경의 경우, 데이터를 다른 샤드 구성의 새 인덱스로 재색인해야 할 수 있습니다.
일반적인 함정 및 피하는 방법
- 맹목적인 과도한 샤드 생성: 작은 클러스터에서 데이터 1GB당 1개의 샤드를 생성하여 과도한 오버헤드를 초래하는 경우. 피하기: 합리적인 목표에서 시작하고 데이터가 증가함에 따라 샤드를 확장하십시오.
- 인덱스의 샤드 부족: 매우 큰 인덱스에 1-3개의 샤드만 있어 병렬화 및 확장성을 제한하는 경우. 피하기: 데이터 볼륨과 노드 용량을 기반으로 계산하십시오.
- 성장 예측 무시: 미래의 수집을 고려하지 않고 현재 데이터에 맞춰 크기를 조정하는 경우. 피하기: 항상 데이터의 수명 동안 예상되는 데이터 성장을 고려하십시오.
- 모니터링 부족: 설정하고 잊어버리는 경우. 샤드 크기, 노드 리소스 및 쿼리 성능은 시간이 지남에 따라 변합니다. 피하기: 주요 지표에 대한 강력한 모니터링 및 경고를 구현하십시오.
- 경험 법칙 맹목적으로 따르기: 10GB-50GB 규칙은 지침일 뿐 엄격한 법이 아닙니다. 특정 워크로드에 따라 변동될 수 있습니다. 피하기: 항상 실제 데이터 및 사용 패턴을 통해 일반적인 권장 사항을 검증하십시오.
결론
Elasticsearch 샤드 크기 조정은 성능이 뛰어나고 확장 가능하며 탄력적인 클러스터를 구축하는 데 있어 미묘하지만 중요한 측면입니다. 이는 병렬 처리를 최대화하고 관리 오버헤드를 최소화하는 섬세한 균형을 포함합니다. 샤드 크기 조정에 영향을 미치는 요소, 다양한 구성의 장단점을 이해하고 계산, 테스트 및 모니터링의 반복적인 전략을 구현함으로써 특정 요구 사항에 맞는 최적의 균형을 달성할 수 있습니다.
클러스터의 요구 사항은 진화한다는 것을 기억하십시오. 정기적인 모니터링과 샤드 크기 조정 전략을 조정하려는 의지는 데이터와 워크로드가 증가함에 따라 건강하고 고성능의 Elasticsearch 환경을 유지하는 데 핵심입니다.