챕터 1~2에서는 인덱스와 도큐먼트 CRUD, 인덱싱, 도큐먼트 검색 등 인덱스와 도큐먼트 수준에서 OpenSearch에 대해 살펴봤다. 챕터 3에서는 아키텍처 수준에서 OpenSearch의 분산 시스템 구성을 알아보고, OpenSearch가 어떻게 대량의 인덱스와 도큐먼트를 안정적으로 처리하고 있는지 알아볼 것이다.
OpenSearch가 데이터를 분산 처리하기 위해 사용하는 분산 아키텍처의 핵심 구성 요소는 다음과 같다.
출처: https://codingexplained.com/coding/elasticsearch/introduction-elasticsearch-architecture
클러스터는 노드의 집합이며, 노드는 클러스터를 구성하는 하나의 OpenSearch 인스턴스로써 도큐먼트가 저장되는 곳이다. 쉽게 말해 노드는 OpenSearch가 설치된 물리 혹은 논리(가상) 서버다. 일반적으로 물리적인 서버 하나에 노드 하나를 설치하는 방식을 권장하지만, 단일 서버에 복수의 노드를 설치해도 된다. 클러스터와 노드는 모두 고유한 이름으로 식별된다.
클러스터는 도큐먼트를 여러 노드에 분산시켜 저장할 수 있고, 모든 노드는 클러스터의 인덱싱 및 도큐먼트 검색 기능에 참여한다. OpenSearch에는 다양한 노드 타입이 있으며, 타입에 따라 수행하는 역할이 다르다. 하나의 노드에 복수의 타입을 할당할 수 있다. 노드 타입에 대해서는 3.2에서 자세히 설명할 예정이다.
노드와 외부 클라이언트 간의 통신은 Application 계층에서 HTTP 프로토콜로 동작하는 반면, 클러스터 내부에 있는 노드 간의 통신은 Transport 계층에서 동작한다. 외부 클라이언트가 REST API를 사용하여 클러스터에 요청을 전송하면 특정 타입의 노드는 해당 요청을 수신하고, 필요한 경우 Transport 계층을 사용하여 다른 노드로 추가 작업을 요청한다. 기본적으로 모든 노드는 외부 클라이언트의 HTTP 요청을 처리할 수 있지만, 클라이언트의 HTTP 요청를 처리하는 역할은 특정 타입의 노드만 수행하도록 제한된다.
출처: https://nidhig631.medium.com/primary-shards-replica-shards-in-elasticsearch-269343324f86
OpenSearch가 확장성이 뛰어난 이유 중 하나는 샤딩(Sharding) 때문이다. 샤딩은 데이터를 여러 개의 조각으로 나눠 분산 저장하여 관리하는 기술이며, 샤드란 샤딩을 통해 나눠진 데이터 블록이다. OpenSearch에서는 인덱스를 샤딩하여 샤드로 관리하고, 노드는 복수의 샤드로 구성된다. 앞서 도큐먼트를 인덱스에 저장한다고 했지만, 사실 인덱스는 논리적 단위이며 실제 도큐먼트의 인덱싱과 검색은 샤드에서 이뤄진다. 즉 분산된 샤드를 하나의 논리적 단위로 묶은 것이 인덱스다.
OpenSearch에서 샤드는 왜 필요할까? 다음과 같은 상황을 가정해보자. 1TB 크기의 인덱스에 복수의 도큐먼트가 저장되어 있고, 클러스터에는 총 2개의 노드가 있으며, 각 노드의 여유 저장 공간은 512GB다. 즉 인덱스를 하나의 노드에 저장할 수 없는 상황이다. 인덱스의 크기가 단일 노드의 하드웨어 리소스 제한을 초과하는 경우 인덱스를 샤딩하여 문제를 해결할 수 있다. 앞선 예의 경우, 다음 그림처럼 1TB 인덱스를 256GB 도큐먼트 묶음 4개로 나눈 후에 노드 2개에 분산시켜 저장하면 된다.
OpenSearch는 기본적으로 샤드 복제를 지원한다. 샤드를 복제하면, 원본은 프라이머리 샤드, 복제본은 레플리카 샤드(또는 레플리카)라고 불린다. 프라이머리 샤드와 레플리카 샤드에 대해서는 3.3에서 자세히 설명할 예정이다.
샤딩이 필요한 이유를 정리하면 다음과 같다.
인덱스의 샤드 개수는 인덱스를 생성할 때 선택적으로 지정할 수 있으며, 기본적으로는 인덱스 하나에 5개의 샤드가 생성된다. 샤드 개수는 클러스터의 하드웨어 스펙과 인덱스의 데이터량 등을 고려하여 적절한 값으로 설정하면 된다.
ℹ️ 과거 버전에서는 number of shards 의 default 가 5였다. 하지만 overshard 문제 때문에, 최근에 1로 변경되었다. ℹ️ overshard 란 인덱스에 저장된 데이터 대비 shard 가 너무 잘게 쪼개져 있어서 불필요하게 성능의 손해가 발생하는 것을 말한다.인덱스가 생성된 후에는 샤드 개수를 변경할 수 없다. 그러나 원하는 샤드 개수로 새로운 인덱스를 만들고, 기존 인덱스의 데이터를 새로운 인덱스로 이동시켜서 목적을 달성할 수는 있다.
인덱스의 샤드 개수를 변경할 수 없는 이유는 OpenSearch의 라우팅 방식 때문이다. 도큐먼트를 저장할 샤드를 결정하는 것을 라우팅이라고 한다. 도큐먼트는 기본적으로 모든 노드에 걸쳐 고르게 분산되어 저장되기 때문에 하나의 샤드에 많은 데이터가 몰리지 않는다. 라우팅은 기본적으로 자동 처리되며, OpenSearch에서는 다음 공식을 사용하여 도큐먼트가 저장될 샤드를 결정한다.
shard = hash(_routing) % 프라이머리 샤드 개수
기본적으로 _routing
값은 저장하려는 도큐먼트의 ID와 동일하다. _routing
값은 해시 함수를 거쳐 숫자로 변환되고, 이것을 프라이머리 샤드 개수로 나눈 나머지 값이 바로 도큐먼트가 저장될 샤드 넘버다.
_routing
값을 직접 지정할 수도 있는데, 이를 커스텀 라우팅이라고 한다. 커스텀 라우팅을 사용하면 같은 _routing
값을 공유하는 도큐먼트들을 동일한 샤드에 저장할 수 있다. 그러나 커스텀 라우팅의 경우 몇 가지 주의해야 할 부분이 있다. 그 중 하나는 도큐먼트가 프라이머리 샤드에 고르게 분산되지 않을 수 있다는 것이다. 예를 들어, movie 인덱스에서 genre를 _routing
값으로 사용하는 경우, 대부분의 영화가 같은 genre라면 도큐먼트는 특정 샤드에 몰릴 수 밖에 없다.
라우팅 공식에 프라이머리 샤드 개수가 포함되어 있으므로, 인덱스의 샤드 개수를 변경하면 도큐먼트에 대한 라우팅 공식 실행 결과도 바뀌게 된다. 라우팅 공식은 도큐먼트를 ID로 검색할 때도 사용되는데, 샤드 개수를 변경하는 경우 도큐먼트가 저장될 때와 검색될 때의 라우팅 공식이 달라지게 되고, 그 결과 도큐먼트를 찾지 못할 수도 있다. 이것이 인덱스의 샤드 개수를 변경할 수 없는 이유다. OpenSearch의 기본 라우팅 공식을 사용해서 도큐먼트를 인덱싱한 후에 동일한 인덱스에 커스텀 라우팅을 도입하는 경우에도 동일한 문제가 발생할 수 있다.
출처: https://fdv.github.io/running-elasticsearch-fun-profit/003-about-lucene/003-about-lucene.html
위의 그림처럼 OpenSearch 샤드는 하나의 Lucene 인스턴스다. Lucene 인스턴스는 여러 개의 세그먼트를 포함하고 있다. 세그먼트는 OpenSearch에서 인덱스가 물리적으로 저장되는 가장 작은 단위로, 세그먼트 내부에는 인덱싱된 데이터가 역색인 구조로 저장되어 있다. 기본적으로 인덱싱된 도큐먼트는 하나의 세그먼트로 저장된다. Lucene 인덱스는 검색 요청이 들어오면 모든 세그먼트에 걸쳐 순차적으로 검색을 수행하고, 이를 통합해서 하나의 결과로 응답한다.
세그먼트는 한 번 디스크에 저장되면 수정이 불가능한 불변 데이터(Immutable)다. 도큐먼트를 수정할 경우 도큐먼트가 포함된 세그먼트를 변경하지 않고, 수정 사항이 반영된 새로운 세그먼트를 생성한 다음 기존 세그먼트를 삭제하는 방식을 활용한다. 도큐먼트를 삭제하는 경우에도 세그먼트 내의 도큐먼트를 실제로 삭제하지 않고, 삭제할 도큐먼트라고 표시만 해둔 다음 검색할 때는 해당 도큐먼트를 읽지 않도록 처리한다.
세그먼트에 대한 검색은 병렬적으로 수행될 수 없기 때문에 세그먼트 수가 많을수록 검색 속도가 느려진다. 그래서 Lucene은 검색 성능을 높이기 위해 정기적으로 백그라운드에서 세그먼트 파일을 물리적으로 하나의 큰 세그먼트 파일로 병합하고, 삭제 표시한 도큐먼트를 실제로 세그먼트에서 삭제한다. 이를 세그먼트 병합이라고 한다. 세그먼트 병합은 OpenSearch API로 트리거할 수도 있다. 세그먼트 병합은 물리적인 저장 공간에서 이뤄지기 때문에 많은 CPU와 I/O 리소스를 사용한다. 대량의 데이터 인덱싱을 수행할 때는 세그먼트 병합을 비활성화하는 것이 좋고, 적절한 세그먼트 병합 정책과 스케쥴러를 활용하여 서버 성능을 최적화할 수도 있다.
Lucene이 세그먼트를 생성하고 병합하는 방법에 대한 구체적인 설명은 공식 문서를 참고하자.(https://lucene.apache.org/core/9_4_2/index.html)
앞서 노드는 타입에 따라 수행하는 역할이 다르다고 했다. OpenSearch에서 제공하는 노드 타입에 대해 알아보자.
기본적으로 모든 노드는 어떤 타입도 될 수 있으며, 다양한 역할을 수행할 수 있다. 노드에 OpenSearch를 설치하고 설정 파일을 수정하지 않으면, 해당 노드는 기본적으로 모든 역할을 수행하게 된다. OpenSearch 설정 파일에서 노드 타입을 지정해줄 경우 하나의 역할만 수행하는 노드가 되는데, 이 노드를 전용 노드라고 부른다.
출처: https://hevodata.com/learn/elasticsearch-ingest-pipeline/
출처: https://levelup.gitconnected.com/elastic-search-simplified-part-2-342a55a1a7c7
_routing
값이 포함된 경우 _routing
을 통해 어떤 노드의 어떤 샤드가 해당 데이터를 갖고 있는지 알 수 있으므로, 해당 노드에게만 쿼리를 요청)3.1.2에서 설명한 레플리카 샤드에 대해 자세히 알아보자.
출처: https://codingexplained.com/coding/elasticsearch/understanding-replication-in-elasticsearch
레플리카 샤드의 주된 목적은 노드나 샤드에 장애가 발생했을 경우에 백업 역할을 수행해서 고가용성을 제공하는 것이다. 고가용성을 실현하기 위해 레플리카 샤드는 프라이머리 샤드와 같은 노드에 할당되지 않는다. 즉 노드 하나가 클러스터를 이탈하더라도 다른 노드에 프라이머리 샤드의 레플리카가 최소한 1개 이상 존재하기 때문에 요청에 정상적으로 응답할 수 있다.
또한 부수적인 목적으로, 레플리카 샤드는 OpenSearch의 검색 성능을 높여준다. 프라이머리 샤드가 위치한 노드에 부하가 심해 응답이 느린 경우, 해당 프라이머리 샤드의 레플리카 샤드가 위치한 다른 노드에 대신 요청해 좀 더 빠른 검색을 수행할 수 있다. 부하 상태 노드에 추가적인 부하를 주는 것을 막을 수 있으므로, 클러스터의 전체적인 처리 성능 안정성도 높일 수 있다. 클러스터에 검색 요청이 많다면 인덱스 당 두 개 이상의 레플리카 샤드를 할당해서 검색 성능을 높이는 것이 좋다.
레플리카 샤드 개수는 인덱스를 생성할 때 정의되며, 기본적으로 프라이머리 샤드 한 개 당 레플리카 샤드 한 개가 생성된다. 즉 기본 설정으로 인덱스를 생성하는 경우, 프라이머리 샤드 5개와 레플리카 샤드 5개를 합쳐서 총 10개의 샤드가 생성된다.
출처: https://codingexplained.com/coding/elasticsearch/understanding-replication-in-elasticsearch
프라이머리 샤드는 여러 개의 레플리카 샤드로 복제될 수 있는데, 모든 레플리카 샤드는 프라이머리 샤드와 동기화된 상태를 유지해야 한다. 레플리카 샤드 그룹이 프라이머리 샤드와 동일한 상태를 유지하지 못할 경우, 쿼리 결과의 일관성이 떨어지게 된다. 예를 들어 도큐먼트가 레플리카 샤드 A에서만 삭제되었다면 A에서 쿼리가 수행될 경우에는 도큐먼트를 읽어올 수 없지만, 다른 레플리카 샤드에서 쿼리가 수행될 경우에는 도큐먼트를 읽어올 수 없게 된다.
OpenSearch는 모든 샤드를 동기화하기 위해 프라이머리 샤드를 모든 인덱싱 작업의 진입점으로 사용한다. 즉 도큐먼트 추가, 수정, 삭제 등 인덱스에 영향을 미치는 모든 요청은 가장 먼저 프라이머리 샤드로 전달된다. 프라이머리 샤드는 다음과 같은 과정을 거쳐 레플리카 샤드와 동기화된 상태를 유지한다.
number
타입으로 매핑된 필드에 object
타입이 요청된 경우)1~4를 처리하던 중에 프라이머리 샤드 또는 레플리카 샤드에 장애가 발생할 수도 있다. 프라이머리 샤드에 장애가 발생한 경우 해당 샤드를 호스팅하는 노드는 클러스터 매니저에게 메시지를 전송한다. 클러스터 매니저가 레플리카 샤드 중 하나를 새로운 프라이머리 샤드로 승격시키면, 인덱싱 작업은 새로운 프라이머리 샤드로 전송된다. 또한 클러스터 매니저는 노드 상태를 모니터링하여 프라이머리 샤드를 사전에 강등시킬 수도 있다.
프라이머리 샤드에서 작업이 성공했음에도 불구하고, 레플리카 샤드에서 작업이 실패할 수도 있다. 이 경우 프라이머리 샤드는 문제가 있는 샤드를 in-sync 레플리카 셋에서 제거해달라고 클러스터 매니저에게 요청한다. 클러스터 매니저가 샤드 제거를 승인한 경우에만 프라이머리 샤드는 최종적으로 클라이언트의 요청을 승인한다. 이후 클러스터 매니저는 시스템을 정상적인 상태로 복원하기 위해 다른 노드에 새로운 레플리카 샤드를 생성할 것을 요청한다.
Elasticvue는 다음과 같은 기능을 제공하는 OpenSearch 클라이언트다.
크롬 확장 프로그램으로 쉽게 설치할 수 있고, 복잡한 환경 설정이 필요 없다는 장점이 있다. 다음 링크를 클릭해서 크롬 확장 프로그램에 추가하고, 실행해보자.
https://chrome.google.com/webstore/detail/elasticvue/hkedbapjpblbodpgbajblpnlpenaebaa
Elasticvue를 실행하면 다음과 같은 Setup 화면이 뜬다. Uri에 OpenSearch REST API 주소를 입력하고 CONNECT를 누르자.
다음과 같은 화면이 뜨면 연결에 성공한 것이다.
클러스터, 노드, 샤드 모니터링이 필요한 경우 Elasticvue를 활용해보자.
챕터 1.1에서는 EC2 인스턴스 한 대로 싱글 노드 클러스터를 구성했었다. 챕터 3.4에서는 EC2 인스턴스 여러 대에 OpenSearch 인스턴스를 한 개씩 설치하여 멀티 노드 클러스터를 구성해 볼 것이다. EC2 인스턴스 한 대에 여러 개의 OpenSearch 인스턴스를 설치할 수도 있지만, OpenSearch에서 권장하는 방법은 아니다.
지금부터 다음과 같은 4노드 클러스터를 구성할 것이다.
출처: https://opensearch.org/docs/latest/opensearch/cluster/
4노드 클러스터를 구성하려면 EC2 인스턴스 4대가 필요하다. EC2 인스턴스 4개를 띄우고, 모든 인스턴스에 한 번씩 접속해서 OpenSearch를 설치하는 것은 번거로운 일이다. 반면 AMI를 활용하면 클릭 몇 번으로 OpenSearch가 미리 설치된 EC2 인스턴스를 시작할 수 있다. AMI는 EC2 인스턴스의 소프트웨어 구성이 정의된 템플릿이며, 기본적으로 EC2 인스턴스에 연결된 모든 EBS 볼륨의 상태도 같이 복제된다. 즉 AMI를 사용하면 특정 EC2 인스턴스와 똑같은 환경의 인스턴스를 시작할 수 있다.
EFK로 서버 로그 수집하기 강의자료
의 4.1.1~4.1.3 과 4.1.9 를 따라한다.ERROR: [2] bootstrap checks failed
[1]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]
EC2 콘솔에서 OpenSearch가 설치된 EC2 인스턴스를 선택하고 (한국어 콘솔의 경우) 우측 상단의 작업
→ 이미지 및 템플릿
→ 이미지 생성
버튼을 눌러 AMI를 생성하자. AMI는 생성 요청 후 사용 가능
상태로 바뀌기까지 약 5~10분 가량의 시간이 걸린다.
AMI를 사용하여 인스턴스 4대를 시작하자.
헷갈리지 않도록 인스턴스 이름에 노드 타입을 추가해주자.
모든 인스턴스 대상으로 OpenSearch config를 수정해줘야 한다. config 파일 경로는 다음과 같다.
$OPENSEARCH_HOME/config/opensearch.yml
config에는 다음 속성 값을 수정해주면 된다.
cluster.name
: 클러스터 이름node.name
: 노드 이름node.roles
: 노드 타입network.host
: 노드의 IP 주소discovery.seed_hosts
: 클러스터에 속한 클러스터 매니저 또는 후보 노드의 IP 주소 목록discovery.seed_hosts
에 설정된 IP 주소로 클러스터 매니저 또는 후보 노드를 찾고, 해당 노드를 클러스터로 바인딩하는 과정을 디스커버리라고 한다.cluster.initial_cluster_manager_nodes
: 클러스터를 맨 처음 실행할 때, 최초로 뜨는 node.name 최초로 기동하는 cluster_manager 서버가 자기 자신의 node.name 을 입력하면 된다.de-opensearch-cluster-practice_manager
EC2 인스턴스에 접속해서 다음과 같이 OpenSearch config를 수정하고 $ sudo systemctl restart opensearch.service
로 OpenSearch 노드를 재시작하자.
plugins.security.disabled: true
cluster.name: opensearch-cluster
node.name: opensearch-cluster_manager
node.roles: [ cluster_manager ]
network.host: 0.0.0.0
discovery.seed_hosts: [0.0.0.0]
cluster.initial_cluster_manager_nodes: ["opensearch-cluster_manager"]
Elasticvue에 클러스터 매니저 노드를 연결하고 NODES 탭을 클릭해보자. 클러스터에 opensearch-cluster_manager
노드가 바인딩된 것을 확인할 수 있다.
de-opensearch-cluster-practice_data1
EC2 인스턴스에 접속해서 다음과 같이 OpenSearch config를 수정하고 $ sudo systemctl restart opensearch.service
로 OpenSearch 노드를 재시작하자.
plugins.security.disabled: true
cluster.name: opensearch-cluster
node.name: opensearch-d1
node.roles: [ data, ingest ]
network.host: 0.0.0.0
discovery.seed_hosts: ["<CLUSTER_MANAGER_NODE_PUBLIC_IP>"]
Elasticvue의 NODES 탭을 새로고침하면, 클러스터에 opensearch-d1
노드가 추가 바인딩된 것을 확인할 수 있다.
de-opensearch-cluster-practice_data2
EC2 인스턴스에 접속해서 다음과 같이 OpenSearch config를 수정하고 $ sudo systemctl restart opensearch.service
로 OpenSearch 노드를 재시작하자.
plugins.security.disabled: true
cluster.name: opensearch-cluster
node.name: opensearch-d2
node.roles: [ data, ingest ]
network.host: 0.0.0.0
discovery.seed_hosts: ["<CLUSTER_MANAGER_NODE_PUBLIC_IP>"]
Elasticvue의 NODES 탭을 새로고침하면, 클러스터에 opensearch-d2
노드가 추가 바인딩된 것을 확인할 수 있다.
de-opensearch-cluster-practice_coordinator
EC2 인스턴스에 접속해서 다음과 같이 OpenSearch config를 수정하고 $ sudo systemctl restart opensearch.service
로 OpenSearch 노드를 재시작하자.
모든 노드는 코디네이터 노드 역할을 수행하므로, node.roles
를 빈 배열로 설정하면 해당 노드는 코디네이터 역할만 수행하는 코디네이터 전용 노드가 된다.
plugins.security.disabled: true
cluster.name: opensearch-cluster
node.name: opensearch-c1
node.roles: []
network.host: 0.0.0.0
discovery.seed_hosts: ["<CLUSTER_MANAGER_NODE_PUBLIC_IP>"]
Elasticvue의 NODES 탭을 새로고침하면, 클러스터에 opensearch-c1
노드가 추가 바인딩된 것을 확인할 수 있다.
opensearch-cluster_manager
노드가 실행중인 EC2 인스턴스에 접속해서 다음 명령어로 클러스터 매니저 노드를 중지시켜보자.
$ sudo systemctl stop opensearch.service
Elasticvue의 NODES 탭을 새로고침하면, 노드를 찾을 수 없다는 화면이 보일 것이다.
Elasticvue를 opensearch-c1
노드의 public IP로 연결할 경우 코디네이터 노드와 해당 노드에 포함된 샤드의 정보는 확인할 수 있지만, 클러스터, 노드, 인덱스의 정보는 확인할 수 없다. 클러스터 매니저 노드는 클러스터 설정, 인덱스 설정, 노드 상태를 관리하는 역할을 담당하기 때문에 매니저 노드가 없는 상황에서는 Elasticvue도 해당 정보를 읽어올 수 없다.
{
"error": {
"root_cause": [
{
"type": "cluster_manager_not_discovered_exception",
"reason": null
}
],
"type": "cluster_manager_not_discovered_exception",
"reason": null
},
"status": 503
}
클러스터 매니저 노드에 장애가 발생하는 상황에 대비하기 위해서는 클러스터 매니저 후보 노드를 설정해둬야 한다. node.roles
에 cluster_manager
를 포함하는 경우 클러스터 매니저 후보 역할을 수행하게 된다.
opensearch-d2
노드의 node.roles
를 다음과 같이 수정하고 노드를 재시작하자.
node.roles: [ data, ingest, cluster_manager ]
모든 노드의 discovery.seed_hosts
에 opensearch-d2
노드의 IP 주소가 등록되어 있지 않기 때문에 discovery에 실패하게 된다. 따라서 Elasticvue에서는 여전히 클러스터 정보를 읽어올 수 없을 것이다. (Elasticvue는 코디네이터 노드에 연결된 상태) 이 경우 opensearch-cluster_manager
노드를 재시작해야 클러스터를 활성화시킬 수 있다. 이후 Elasticvue를 확인해보면 opensearch-d2
노드에 클러스터 매니저 후보(master eligile) 역할이 추가된 것을 확인할 수 있을 것이다.
opensearch-cluster_manager
노드를 다시 중지시켜보자. opensearch-d2
가 새로운 클러스터 매니저 노드로 선출되고 클러스터가 정상화될 것이라는 예상과는 달리 클러스터는 여전히 작동을 멈춘 상태다. 이유는 에러 로그를 통해 알 수 있는데, 클러스터 매니저 노드 선출에 필요한 최소 후보 노드 수를 충족하지 못했기 때문이다.
which is not a quorum;
[2022-12-25T09:51:57,621][WARN ][o.o.c.c.ClusterFormationFailureHelper] [opensearch-d2] cluster-manager not discovered or elected yet, an election requires a node with id [k3y5PllfSzCZQKACMQN4tg], have discovered [{opensearch-d2}{OpwmNmeiQSCd19yKmZfKfQ}{Q-z5SfsoSB2-U4o5GLVVwg}{172.31.100.141}{172.31.100.141:9300}{dim}{shard_indexing_pressure_enabled=true}] which is not a quorum; discovery will continue using [13.125.209.78:9300] from hosts providers and [{opensearch-d2}{OpwmNmeiQSCd19yKmZfKfQ}{Q-z5SfsoSB2-U4o5GLVVwg}{172.31.100.141}{172.31.100.141:9300}{dim}{shard_indexing_pressure_enabled=true}, {opensearch-cluster_manager}{k3y5PllfSzCZQKACMQN4tg}{mTQPHU7tTNOV8YfUONlEuQ}{172.31.100.191}{172.31.100.191:9300}{m}{shard_indexing_pressure_enabled=true}] from last-known cluster state; node term 10, last-accepted version 84 in term 10
최소 후보 노드 수를 충족하기 위해 opensearch-d1
노드의 node.roles
를 다음과 같이 수정하고, opensearch-cluster_manager
노드와 opensearch-d1
노드를 모두 재시작하자.
node.roles: [ data, ingest, cluster_manager ]
모든 노드가 클러스터링된 것을 확인한 다음 opensearch-cluster_manager
노드를 다시 중지시켜보자. Elasticvue의 NODES 탭을 새로고침하면 다음과 같이 opensearch-d1
(또는 opensearch-d2
) 노드가 매니저 노드로 선출된 것을 확인할 수 있다.
이 상태에서 opensearch-cluster_manager
노드를 다시 클러스터에 참여시키려면 discovery.seed_hosts
를 다음과 같이 수정하고 노드를 재시작해줘야 한다.
discovery.seed_hosts: ["<DATA2_NODE_PUBLIC_IP>"]
opensearch-cluster_manager
노드가 다시 클러스터에 참여해도 이미 선출된 매니저 노드는 바뀌지 않고, 그대로 opensearch-d1
노드인 것을 확인할 수 있다.
안전한 클러스터 운영을 위해 클러스터 매니저 후보 노드는 최소 3개 이상(클러스터 매니저 노드 포함)으로 설정하는 것이 좋다. 또한 discovery.seed_hosts
에는 모든 클러스터 매니저 후보 노드를 포함시키는 것이 좋다.
OpenSearch와 달리 ElasticSearch의 경우 7.3 버전부터 투표 전용 노드 타입을 지원한다. 클러스터 매니저 후보 노드 중에서 매니저 선출 투표에는 참여할 수 있지만, 본인은 매니저 노드가 될 수 없는 노드를 투표 전용 노드라고 한다. 투표 전용 노드는 매니저 노드가 될 수 없기 때문에 매니저 후보 노드보다 부담없이 사용할 수 있으며, 대다수의 매니저 후보 노드들에 장애가 발생했을 때도 매니저 후보 선출 과정이 정상적으로 진행될 수 있도록 돕는다.
ElasticSearch에서 투표 전용 노드를 만들고 싶다면 node.roles
를 다음과 같이 설정해주면 된다.
node.roles: [ cluster_manager, voting_only ]
PUT /_ingest/pipeline/test-pipeline
API로 인제스트 파이프라인을 생성할 수 있다. Elasticvue의 REST 클라이언트를 사용해서 요청해보자.
요청 본문에서 processors
필드는 리스트 타입으로, 여러 개의 프로세서를 정의할 수 있고, 해당 프로세서들은 리스트에 정의된 순서대로 실행된다. set
프로세서는 특정 필드의 값을 추가 또는 수정하는 작업을 수행하고, lowercase
프로세서는 string을 소문자로 변환하는 작업을 수행한다.
$ curl -XPUT "$OPENSEARCH_REST_API/_ingest/pipeline/test-pipeline?pretty=true" \
-H "Content-Type: application/json" \
-d '
{
"processors": [
{
"set": {
"field": "field1",
"value": 10
}
},
{
"lowercase": {
"field": "field2"
}
}
]
}
'
test-pipeline
파이프라인을 사용해서 도큐먼트를 test1
인덱스에 인덱싱해보자.
$ curl -XPUT "$OPENSEARCH_REST_API/test1/_doc/1?pipeline=test-pipeline&pretty=true" \
-H "Content-Type: application/json" \
-d '
{
"field1": "test",
"field2": "Hello, OpenSearch!"
}
'
인덱싱한 도큐먼트의 field1
은 10으로, field2
는 모두 소문자로 변경된 것을 확인할 수 있다.