본문 바로가기
WIKI 기술 지식 베이스

Creating a cluster

원문 보기 위키 갱신

출처: 문서

본문

클러스터 생성하기

OpenSearch를 본격적으로 살펴보고 데이터를 검색하고 집계하기 전에, 먼저 OpenSearch 클러스터를 만들어야 해요.

OpenSearch는 단일 노드 클러스터로도, 멀티 노드 클러스터로도 운영할 수 있어요. 두 경우를 설정하는 절차는 일반적으로 상당히 비슷해요. 이 페이지에서는 멀티 노드 클러스터를 만들고 설정하는 방법을 보여주지만, 몇 가지 사소한 조정만 거치면 같은 절차를 그대로 따라 단일 노드 클러스터를 만들 수도 있어요.

요구 사항에 맞게 OpenSearch 클러스터를 만들고 배포하려면 노드 디스커버리와 클러스터 형성이 어떻게 동작하는지, 그리고 어떤 설정이 이를 제어하는지 이해하는 게 중요해요.

클러스터를 설계하는 방법은 다양해요. 다음 그림은 세 개의 전용 클러스터 매니저 노드(cluster-manager-eligible 노드 두 개와 선출된 리더 하나), 세 개의 데이터 노드, 그리고 하나의 전용 코디네이팅 노드로 이루어진 7노드 클러스터를 포함하는 기본 아키텍처를 보여줘요.

멀티 노드 클러스터 아키텍처 다이어그램

예전의 "master node"는 이제 클러스터 매니저 노드라고 불려요. {: .note }

노드

다음 표는 노드 타입에 대한 간략한 설명을 제공해요.

노드 타입 설명 프로덕션을 위한 모범 사례
클러스터 매니저 노드 클러스터의 전반적인 운영을 관리하고 클러스터 상태를 추적해요. 여기에는 인덱스 생성과 삭제, 클러스터에 합류하거나 떠나는 노드 추적, 클러스터 내 각 노드의 상태 확인(ping 요청 실행), 노드에 샤드 할당이 포함돼요. 세 개의 서로 다른 존에 전용 클러스터 매니저 노드 세 개를 두는 것이 거의 모든 프로덕션 사용 사례에 맞는 접근 방식이에요. 이 구성 덕분에 클러스터가 쿼럼을 잃는 일은 없어요. 한 노드가 다운되거나 약간의 유지 보수가 필요한 경우를 제외하면 두 노드는 대부분의 시간 동안 유휴 상태로 있게 돼요.
cluster-manager-eligible 노드 투표 과정을 통해 그들 중 하나의 노드를 클러스터 매니저 노드로 선출해요. 프로덕션 클러스터라면 전용 클러스터 매니저 노드를 갖추고 있는지 꼭 확인하세요. 전용 노드 타입을 만드는 방법은 다른 모든 노드 타입을 false로 표시하는 거예요. 이 경우 다른 모든 노드를 cluster manager eligible이 아닌 것으로 표시해야 해요.
데이터 노드 데이터를 저장하고 검색해요. 로컬 샤드에서 모든 데이터 관련 작업(인덱싱, 검색, 집계)을 수행해요. 이 노드들은 클러스터의 워커 노드이며 다른 어떤 노드 타입보다 많은 디스크 공간이 필요해요. 데이터 노드를 추가할 때는 존 간에 균형을 유지하세요. 예를 들어 존이 세 개라면 데이터 노드를 3의 배수로, 존마다 하나씩 추가하세요. 스토리지와 RAM이 풍부한 노드를 사용하는 걸 권장해요.
Ingest 노드 클러스터에 저장하기 전에 데이터를 전처리해요. 데이터를 인덱스에 추가하기 전에 변환하는 ingest 파이프라인을 실행해요. 많은 데이터를 수집하고 복잡한 ingest 파이프라인을 실행할 계획이라면 전용 ingest 노드를 사용하는 걸 권장해요. 선택적으로 데이터 노드에서 인덱싱을 오프로드해서 데이터 노드가 검색과 집계에만 쓰이게 만들 수도 있어요.
코디네이팅 노드 클라이언트 요청을 데이터 노드의 샤드들에 위임하고, 결과를 모아 하나의 최종 결과로 집계한 다음 그 결과를 클라이언트에 다시 돌려보내요. 검색이 많은 워크로드에서 병목을 막으려면 전용 coordinating-only 노드를 몇 개 두는 게 적절해요. 가능한 한 코어 수가 많은 CPU를 사용하는 걸 권장해요.
동적 노드 머신 러닝(ML) 작업 같은 커스텀 작업을 위해 특정 노드를 지정하여 데이터 노드의 리소스 소비를 막고, 그 결과 OpenSearch 기능에 어떤 영향도 주지 않아요.
Warm 노드 searchable snapshots에 대한 접근을 제공해요. 자주 쓰이는 세그먼트를 캐싱하고 가장 적게 쓰이는 데이터 세그먼트를 제거하는 등의 기법을 활용해서 searchable snapshot 인덱스(예를 들어 Amazon Simple Storage Service [Amazon S3]나 Google Cloud Storage 같은 원격 장기 스토리지 소스에 저장됨)에 접근해요. Warm 노드에는 스냅샷 캐시로 할당된 인덱스가 들어 있어요. 따라서 스토리지 용량(하드 디스크)보다 컴퓨팅(CPU와 메모리)이 더 많은 전용 노드를 사용하는 걸 권장해요.
Search 노드 Search 노드는 search replica 샤드만 호스팅하는 전용 노드로, 검색 워크로드를 인덱싱 워크로드와 분리하는 데 도움이 돼요. Search 노드는 search replica를 호스팅하고 검색 트래픽을 처리하기 때문에, 메모리 최적화 전용 인스턴스에 사용하는 걸 권장해요.

기본적으로 각 노드는 cluster-manager-eligible, data, ingest, coordinating 노드예요. 노드 수를 정하고, 노드 타입을 할당하고, 노드 타입별 하드웨어를 고르는 일은 사용 사례에 따라 달라져요. 데이터를 보관하고 싶은 기간, 문서의 평균 크기, 일반적인 워크로드(인덱싱, 검색, 집계), 기대하는 가격 대비 성능 비율, 감수 가능한 리스크 수준 같은 요소를 반드시 고려해야 해요.

이런 요구 사항을 모두 평가한 다음에는, OpenSearch Benchmark 같은 벤치마크 테스팅 도구로 작은 샘플 클러스터를 프로비저닝하고 다양한 워크로드와 구성으로 테스트를 돌려 보길 권장해요. 이 테스트들의 시스템 및 쿼리 메트릭을 비교하고 분석해서 최적의 아키텍처를 설계하세요.

이 페이지에서는 여러 노드 타입을 다루는 방법을 보여줘요. 앞의 그림과 비슷한 4노드 클러스터가 있다고 가정해요.

OpenSearch Dashboards, OpenSearch Data Prepper 같은 외부 소스의 트래픽은 가용성 순서대로 ingest 노드, 코디네이팅 노드, 데이터 노드로 보내는 게 모범 사례예요. 클러스터 매니저 노드로 트래픽을 직접 보내는 건 권장하지 않아요. {: .note}

사전 준비 사항

시작하기 전에 모든 노드에 OpenSearch를 설치하고 설정해야 해요. 사용 가능한 옵션에 대한 정보는 Installing OpenSearch를 참조하세요.

설치가 끝나면 SSH로 각 노드에 접속한 다음 config/opensearch.yml 파일을 열어요. 이 파일에서 클러스터의 모든 설정을 지정할 수 있어요.

단계 1: 클러스터 이름 짓기

클러스터에 고유한 이름을 지정하세요. 클러스터 이름을 지정하지 않으면 기본값인 opensearch로 설정돼요. 설명이 되는 클러스터 이름을 설정하는 건, 특히 하나의 네트워크 안에서 여러 클러스터를 돌리려 할 때 중요해요.

클러스터 이름을 지정하려면 다음 줄을 변경해요:

#cluster.name: my-application

다음과 같이 바꿔요:

cluster.name: opensearch-cluster

노드들이 합류해서 하나의 클러스터를 형성할 수 있도록, 모든 노드에서 같은 변경을 적용하세요.

단계 2: 클러스터 내 각 노드의 노드 속성 설정하기

클러스터 이름을 정한 다음에는 클러스터 내 각 노드의 노드 속성을 설정해요.

클러스터 매니저 노드

클러스터 매니저 노드에 이름을 지정해 주세요. 이름을 지정하지 않으면 OpenSearch가 자동 생성된 이름을 할당하기 때문에 노드를 모니터링하거나 문제를 해결하기가 어려워져요.

node.name: opensearch-cluster_manager

이 노드가 클러스터 매니저 노드라는 사실은 기본값으로 이미 true로 설정되어 있지만, 명시적으로 지정할 수도 있어요. 클러스터 매니저 노드를 더 쉽게 식별할 수 있도록 노드 역할을 cluster_manager로 설정하세요.

node.roles: [ cluster_manager ]

데이터 노드

두 노드의 이름을 각각 opensearch-d1과 opensearch-d2로 변경하세요:

node.name: opensearch-d1
node.name: opensearch-d2

이 노드들을 데이터 수집에도 함께 쓰이는 cluster-manager-eligible 데이터 노드로 만들 수 있어요:

node.roles: [ data, ingest ]

데이터 노드에 설정하고 싶은 다른 속성이 있다면 그것도 지정할 수 있어요.

코디네이팅 노드

코디네이팅 노드의 이름을 opensearch-c1로 변경하세요:

node.name: opensearch-c1

모든 노드는 기본적으로 코디네이팅 노드예요. 따라서 이 노드를 전용 코디네이팅 노드로 만들려면 node.roles를 빈 리스트로 설정하세요:

node.roles: []

단계 3: 클러스터를 특정 IP 주소에 바인딩하기

network.bind_host는 노드를 바인딩하는 데 사용되는 IP 주소를 정의해요. 기본적으로 OpenSearch는 로컬 호스트에서 리슨하기 때문에 클러스터가 단일 노드로 제한돼요. _local_과 _site_를 사용하면 IPv4든 IPv6든 루프백 또는 사이트 로컬 주소에 바인딩할 수도 있어요:

network.bind_host: [_local_, _site_]

멀티 노드 클러스터를 형성하려면 노드의 IP 주소를 지정하세요:

network.bind_host: <IP address of the node>

이 설정은 반드시 모든 노드에 구성하세요.

단계 4: 클러스터의 디스커버리 호스트와 초기 클러스터 매니저 노드 구성하기

네트워크 호스트 구성을 마쳤으니, 이제 디스커버리 호스트를 구성하고 초기 클러스터 선출에 사용할 클러스터 매니저 노드들을 지정해야 해요. 이때는 IP 주소, 호스트명, 정규화된 호스트명(fully-qualified hostname)이 아니라 노드 이름을 쓴다는 점에 유의하세요.

예를 들어 이 설정은 다음과 같아요:

cluster.initial_cluster_manager_nodes: ["opensearch-cluster_manager"]

Zen Discovery는 unicast를 사용해서 클러스터 내 다른 노드를 찾는 내장 기본 메커니즘이에요.

일반적으로 cluster-manager-eligible 노드들은 모두 discovery.seed_hosts 배열에 추가하면 돼요. 노드가 시작되면 다른 cluster-manager-eligible 노드들을 찾아 어느 노드가 클러스터 매니저인지 판단한 다음, 클러스터 합류를 요청해요.

예를 들어 opensearch-cluster_manager의 경우 이 줄은 대략 다음과 같아요:

discovery.seed_hosts: ["<private IP of opensearch-d1>", "<private IP of opensearch-d2>", "<private IP of opensearch-c1>"]

단계 5: 클러스터 시작하기

구성을 모두 설정한 다음에는 모든 노드에서 OpenSearch를 시작하세요:

sudo systemctl start opensearch.service

tar 아카이브로 OpenSearch를 설치하면 systemd 서비스가 자동으로 생성되지 않아요. Failed to start opensearch.service: Unit not found. 같은 오류가 발생한다면, 서비스를 생성하고 시작하는 방법에 대한 지침을 Run OpenSearch as a service using systemd에서 참조하세요. {: .tip}

그런 다음 로그 파일을 열어 클러스터가 형성되는 과정을 확인해요:

less /var/log/opensearch/opensearch-cluster.log

클러스터로 형성된 모든 노드를 보려면 아무 노드에서나 다음 _cat 쿼리를 수행해요:

curl -XGET https://<private-ip>:9200/_cat/nodes?v -u 'admin:<custom-admin-password>' --insecure
ip             heap.percent ram.percent cpu load_1m load_5m load_15m node.role cluster_manager name
x.x.x.x           13          61   0    0.02    0.04     0.05 mi        *      opensearch-cluster_manager
x.x.x.x           16          60   0    0.06    0.05     0.05 md        -      opensearch-d1
x.x.x.x           34          38   0    0.12    0.07     0.06 md        -      opensearch-d2
x.x.x.x           23          38   0    0.12    0.07     0.06 md        -      opensearch-c1

클러스터를 더 잘 이해하고 모니터링하려면 CAT API를 사용하세요.

(고급) 6단계: 샤드 할당 인식(shard allocation awareness) 또는 강제 인식(forced awareness) 구성

샤드 할당을 더 세밀하게 조정하려면 샤드 할당 인식 또는 강제 인식을 위한 커스텀 노드 속성을 설정할 수 있어요.

샤드 할당 인식(shard allocation awareness)

OpenSearch 노드에 샤드 할당 인식에 사용할 커스텀 노드 속성을 설정할 수 있어요. 예를 들어 각 노드에 zone 속성을 설정해 노드가 위치한 존(zone)을 나타낼 수 있죠. 또한 zone 속성을 사용해 프라이머리 샤드와 그 복제본 샤드가 사용 가능한 서로 다른 존들에 걸쳐 균형 있게 할당되도록 할 수 있어요. 이 시나리오에서 존당 최대 샤드 복사본 수는 ceil (number_of_shard_copies/number_of_distinct_zones)가 돼요.

OpenSearch는 기본적으로 하나의 샤드에 대한 샤드 복사본들을 서로 다른 노드에 할당해요. 존 장애가 발생한 후처럼 존이 1개만 사용 가능한 경우, OpenSearch는 남은 유일한 존에 복제본 샤드를 할당해요. 존당 허용되는 최대 샤드 복사본 수를 계산할 때는 사용 가능한 존(속성 값)만 고려하기 때문이에요.

예를 들어 인덱스에 총 5개의 샤드 복사본(프라이머리 1개, 복제본 4개)이 있고 3개의 서로 다른 존에 노드가 있다면, OpenSearch는 5개의 샤드 복사본을 모두 할당하기 위해 다음을 수행해요:

  • 존당 샤드를 2개 이하로 할당해요. 이를 위해서는 2개 존에 최소 2개의 노드가 필요해요.
  • 마지막 샤드는 세 번째 존에 할당하고, 세 번째 존에는 최소 1개의 노드가 필요해요.

또는 첫 번째 존에 노드 3개, 나머지 존에 각각 노드 1개씩 있다면 OpenSearch는 다음과 같이 할당해요:

  • 첫 번째 존에 샤드 복사본 2개
  • 나머지 2개 존에 샤드 복사본 1개씩

노드가 부족하기 때문에 마지막 샤드 복사본은 할당되지 않은 상태로 남게 돼요.

샤드 할당 인식을 사용하면 한 존의 노드에 장애가 발생하더라도 복제본 샤드가 다른 존들에 분산되어 있다는 점을 안심할 수 있어요. 내결함성 계층이 하나 더 추가되어 존 장애가 발생해도 데이터가 유지되도록 보장해 주거든요.

샤드 할당 인식을 구성하려면 opensearch-d1과 opensearch-d2에 각각 존 속성을 추가하세요:

node.attr.zone: zoneA
node.attr.zone: zoneB

클러스터 설정을 업데이트하세요:

PUT _cluster/settings
{
  "persistent": {
    "cluster.routing.allocation.awareness.attributes": "zone"
  }
}

속성을 쉼표로 구분된 문자열로 제공하면 샤드 할당 인식에 여러 속성을 사용할 수도 있어요. 예를 들어 zone,rack처럼요.

persistent 설정과 transient 설정 중 하나를 사용할 수 있어요. 클러스터 재시작 후에도 유지되는 persistent 설정을 추천해요. transient 설정은 클러스터를 재시작하면 유지되지 않거든요.

샤드 할당 인식은 프라이머리 샤드와 복제본 샤드를 여러 존에 나눠 배치하려고 해요. 하지만 존이 하나만 사용 가능한 경우(예: 존 장애 발생 후)에는 OpenSearch가 남은 유일한 존에 복제본 샤드를 할당해요.

강제 인식(forced awareness)

또 다른 옵션은 프라이머리 샤드와 복제본 샤드가 절대 같은 존에 할당되지 않도록 요구하는 거예요. 이를 강제 인식이라고 해요.

강제 인식을 구성하려면 존 속성의 가능한 모든 값을 지정하세요:

PUT _cluster/settings
{
  "persistent": {
    "cluster.routing.allocation.awareness.attributes": "zone",
    "cluster.routing.allocation.awareness.force.zone.values":["zoneA", "zoneB"]
  }
}

이제 데이터 노드에 장애가 발생하면 강제 인식은 복제본을 같은 존의 노드에 할당하지 않아요. 대신 클러스터는 yellow 상태가 되고, 다른 존의 노드가 온라인이 될 때 비로소 복제본을 할당해요.

이 두 존 아키텍처에서 opensearch-d1과 opensearch-d2의 사용률이 50% 미만이라면, 즉 두 노드 모두 같은 존에 복제본을 할당할 스토리지 용량이 있다면 할당 인식을 사용할 수 있어요. 그렇지 않고 opensearch-d1과 opensearch-d2에 모든 프라이머리 샤드와 복제본 샤드를 담을 용량이 없다면 강제 인식을 사용하면 돼요. 이 방식은 장애가 발생했을 때 OpenSearch가 마지막으로 남은 존에 과부하를 주어 스토리지 부족으로 클러스터가 멈추는 일이 없도록 도와줘요.

할당 인식과 강제 인식 중 무엇을 선택할지는 프라이머리 샤드와 복제본 샤드의 균형을 맞추기 위해 각 존에 얼마나 많은 공간이 필요한지에 따라 달라져요.

복제본 수 강제(replica count enforcement)

모든 존에 걸쳐 샤드가 고르게 분배되도록 강제하고 핫스팟을 피하려면 routing.allocation.awareness.balance 속성을 true로 설정하면 돼요. 이 설정은 opensearch.yml 파일에서 구성할 수 있고, cluster update settings API를 사용해 동적으로 업데이트할 수도 있어요:

PUT _cluster/settings
{
  "persistent": {
    "cluster": {
      "routing.allocation.awareness.balance": "true"
    }
  }
}

routing.allocation.awareness.balance 설정의 기본값은 false예요. true로 설정하면 인덱스의 총 샤드 수가 인식 속성 중 개수가 가장 많은 것의 배수여야 해요. 예를 들어 존(zone)과 랙 ID(rack ID)라는 두 개의 인식 속성이 있는 구성을 생각해 보세요. 존이 2개이고 랙 ID가 3개라고 해보죠. 존 수와 랙 ID 수 중 더 큰 값은 3이에요. 따라서 샤드 수는 3의 배수여야 하고, 그렇지 않으면 OpenSearch가 validation exception을 발생시켜요.

routing.allocation.awareness.balance는 cluster.routing.allocation.awareness.attributes와 cluster.routing.allocation.awareness.force.zone.values가 설정된 경우에만 적용돼요. {: .note}

routing.allocation.awareness.balance는 인덱스를 생성하거나 업데이트하는 모든 작업에 적용돼요. 예를 들어 존 인식(zone-aware) 설정으로 노드 3개, 존 3개짜리 클러스터를 운영한다고 해보죠. 복제본 1개로 인덱스를 생성하려 하거나 인덱스 설정을 복제본 1개로 업데이트하려 하면, 샤드 수가 3의 배수여야 하기 때문에 validation exception과 함께 실패해요. 마찬가지로 샤드 1개, 복제본 없음으로 인덱스 템플릿을 생성하려 해도 같은 이유로 실패해요. 하지만 이 모든 작업에서 샤드 수를 1로, 복제본 수를 2로 설정하면 총 샤드 수가 3이 되어 시도가 성공해요.

(고급) 7단계: 핫-웜(hot-warm) 아키텍처 구성

데이터를 먼저 핫(hot) 노드(빠르고 비싼 노드)에 인덱싱하고, 일정 기간이 지나면 웜(warm) 노드(느리고 저렴한 노드)로 옮기는 핫-웜 아키텍처를 설계할 수 있어요.

거의 업데이트하지 않는 시계열 데이터를 분석하고, 오래된 데이터는 더 저렴한 스토리지에 두고 싶다면 이 아키텍처가 잘 맞을 수 있어요.

이 아키텍처는 스토리지 비용을 절약하는 데 도움이 돼요. 핫 노드 수를 늘려 빠르고 비싼 스토리지를 사용하는 대신, 자주 접근하지 않는 데이터를 위한 웜 노드를 추가하면 되거든요.

핫-웜 스토리지 아키텍처를 구성하려면 opensearch-d1과 opensearch-d2에 각각 temp 속성을 추가하세요:

node.attr.temp: hot
node.attr.temp: warm

속성 이름과 값은 모든 핫 노드와 웜 노드에서 일관되기만 하면 원하는 대로 정할 수 있어요.

핫 노드에 newindex 인덱스를 추가하려면:

PUT newindex
{
  "settings": {
    "index.routing.allocation.require.temp": "hot"
  }
}

newindex의 샤드 할당을 살펴볼까요?

GET _cat/shards/newindex?v
index     shard prirep state      docs store ip         node
new_index 2     p      STARTED       0  230b 10.0.0.225 opensearch-d1
new_index 2     r      UNASSIGNED
new_index 3     p      STARTED       0  230b 10.0.0.225 opensearch-d1
new_index 3     r      UNASSIGNED
new_index 4     p      STARTED       0  230b 10.0.0.225 opensearch-d1
new_index 4     r      UNASSIGNED
new_index 1     p      STARTED       0  230b 10.0.0.225 opensearch-d1
new_index 1     r      UNASSIGNED
new_index 0     p      STARTED       0  230b 10.0.0.225 opensearch-d1
new_index 0     r      UNASSIGNED

이 예제에서는 모든 프라이머리 샤드가 우리의 핫 노드인 opensearch-d1에 할당됐어요. 모든 복제본 샤드는 할당되지 않은(unassigned) 상태인데, 이 인덱스가 핫 노드에만 할당되도록 강제했기 때문이에요.

웜 노드에 oldindex 인덱스를 추가하려면:

PUT oldindex
{
  "settings": {
    "index.routing.allocation.require.temp": "warm"
  }
}

oldindex의 샤드 할당은 다음과 같아요:

GET _cat/shards/oldindex?v
index     shard prirep state      docs store ip        node
old_index 2     p      STARTED       0  230b 10.0.0.74 opensearch-d2
old_index 2     r      UNASSIGNED
old_index 3     p      STARTED       0  230b 10.0.0.74 opensearch-d2
old_index 3     r      UNASSIGNED
old_index 4     p      STARTED       0  230b 10.0.0.74 opensearch-d2
old_index 4     r      UNASSIGNED
old_index 1     p      STARTED       0  230b 10.0.0.74 opensearch-d2
old_index 1     r      UNASSIGNED
old_index 0     p      STARTED       0  230b 10.0.0.74 opensearch-d2
old_index 0     r      UNASSIGNED

이 경우에는 모든 프라이머리 샤드가 opensearch-d2에 할당돼요. 웜 노드가 하나뿐이기 때문에 이번에도 모든 복제본 샤드가 할당되지 않은 상태로 남아요.

널리 쓰이는 방법 중 하나는 인덱스 템플릿을 구성해 index.routing.allocation.require.temp 값을 hot으로 설정하는 거예요. 이렇게 하면 OpenSearch가 가장 최근 데이터를 핫 노드에 저장해요.

그런 다음 Index State Management (ISM) 플러그인을 사용하면 인덱스의 경과 기간을 주기적으로 확인하고 해당 인덱스에 수행할 작업을 지정할 수 있어요. 예를 들어 인덱스가 특정 기간에 도달하면 index.routing.allocation.require.temp 설정을 warm으로 바꿔서 데이터를 핫 노드에서 웜 노드로 자동으로 옮길 수 있죠.

다음 단계

Security 플러그인을 사용 중이라면 앞서 _cat/nodes?v 요청이 초기화 오류로 실패했을 수도 있어요. Security 플러그인 사용에 대한 전체 안내는 보안 구성을 참고하세요.

이 가이드에서 언급한 모든 OpenSearch 설정에 대한 포괄적인 문서는 OpenSearch 구성을 참고하세요. {: .note}

더 알아보기 (Learn more)