본문 바로가기

SearchDeveloper/엘라스틱서치 바이블

[5] 서비스 환경에 클러스터 구성

노드 설정과 노드 역할

노드 역할

https://www.elastic.co/guide/en/elasticsearch/reference/7.17/modules-node.html

-master-eligible node(마스터 후보 노드) : 마스터 후보 중에서 선거를 통해 마스터 노드가 선출된다. 클러스터 관리, 인덱스 생성/삭제, 어떤 샤드를 어떤 노드에 할당한 것인지 정한다.

-coordinating node(조정 노드): 노드는 기본적으로 조정 역할을 수행한다. mode.roles:[] 를 empty 로 두면 조정 역할만 수행한다. (1단계 scatter: 요청을 데이터 노드로 분산시키고, 2단계 gather: 결과 모으기)

-remote_cluster_client: 다른 클러스터에 클라이언트로 붙을 수 있는 노드. 클러스터 간 검색 기능도 가능하고 데이터 복제를 통한 동기화도 할 수 있다.

elasticsearch.yml

ES 7.10~

https://www.elastic.co/guide/en/elasticsearch/reference/current/important-settings.html

-discovery.seed_hosts : 마스터 후보 노드 목록

-cluster.initial_master_nodes : 클러스터 기동 시 첫 마스터 선거를 수행할 후보 노드 목록

-[network.host](https://www.elastic.co/guide/en/elasticsearch/reference/current/modules-network.html#common-network-settings "https://www.elastic.co/guide/en/elasticsearch/reference/current/modules-network.html#common-network-settings") : ES 에 바인딩할 네트워크 주소. publish address 주소에도 적용된다. (기본값: _local_)

  • 0.0.0.0: 모든 네트워크에서 접근 가능

-http.port : 기본값: 9200-9300. 9200 부터 시작해서 선점 중이면 다음 포트를 사용한다.

 

ES 7 미만

discovery.zen: discovery.seed_hosts, cluster.initial_master_nodes 대신 사용한다.

  • [discovery.zen.minimum_master_nodes](https://esbook.kimjmin.net/03-cluster/3.3-master-and-data-nodes "https://esbook.kimjmin.net/03-cluster/3.3-master-and-data-nodes"): 몇 대의 마스터 후보군이 살아있어야 마스터 선출을 수행할지 지정한다. 마스터 후보의 과반 이상으로 지정하지 않으면 split brain 이 일어날 수 있다. 값이 2이면 클러스터 네트워크가 단절됐을 때 마스터가 2개 이상인 클러스터만 살아남는다.
    • 7 버전 이상은 split brain 이 일어나지 않는 구조 (투표 도입으로)
     

힙 메모리 설정 가이드

힙 메모리 설정 위치

7.11 이상이면 config/jvm.options 보단 config/jvm.options.d/ 밑에 heap-size.options 파일을 생성해서 관리하는게 편하다

-Xms32376m
-Xmx32376m

시스템 메모리 절반 이하로 지정하자

왜? 루씬이 커널 시스템 캐시 많이 쓰기 때문에 절반은 운영체제가 캐시로 쓰도록 놔두는 것이 좋다.

힙 크기를 32GB 아래로 지정하자

왜? JVM 이 Compressed OOPs 를 사용할 수 있게. 이게 성능에 영향이 크다.

 

💡 Compressed OOPs (Ordinary Object Pointers) 란?
https://velog.io/@koey_h/MemoryStructure
JVM 이 힙에 생성된 객체에 접근하기 위한 포인터를 OOP 라고 하는데, OOP 는 메모리 주소를 직접 가리킨다.
32bit 환경에선 포인터 1개가 32bit, 64bit 환경에선 포인터1개를 64bit 로 표현한다. 메모리 한 칸은 OS 상관없이 1 byte 를 가지므로 32bit 환경에서는
2^32 byte = (2^2)*(2^30) B = 4GB 까지 사용할 수 있다.

그런데 Compressed OOPs 는 OOP 가 메모리 주소를 직접 가리키는게 아니라 객체의 상대적인 위치 차이만을 나타내는 방식으로, 8 byte 단위로 저장하는 자바 객체 주소를 1byte 로 표현할 수 있어 8배인 32GB 의 메모리를 사용할 수 있다.
= oops 가 object를 referencing 하는 대신 object의 offset을 referencing 한다.

아래 테스트를 통해 Compressed OOPs 가 true인 적용 범위안의 메모리로 설정한다.

hiseo@hiseo ~ % java -Xmx32G -XX:+PrintFlagsFinal 2> /dev/null | grep UseCompressedOops
     bool UseCompressedOops                         = false                               {lp64_product}
hiseo@hiseo ~ % java -Xmx31G -XX:+PrintFlagsFinal 2> /dev/null | grep UseCompressedOops
     bool UseCompressedOops                        := true                                {lp64_product}

 

1byte 로 인코딩된 주소를 디코딩하려면 3bit 시프트 연산 후 힙 영역이 시작되는 기본 주소를 더하는 작업이 필요한다.

zero-based 를 적용하면 기본 주소를 0으로 바꿔줘 더하는 과정이 없어져 성능 상 낫다. (항상 나은건 아니지만)

Compresseed OOPs 최대값 보다는 좀 더 낮은 값이다.

java -XX:+UnlockDiagnosticVMOptions -Xlog:gc+heap+coops=debug -Xmx31G -version

(error) Unrecognized option: -Xlog:gc+heap+coops=debug

  1. -XX:+UnlockDiagnosticVMOptions: 이 옵션은 진단 VM 옵션을 활성화하는 것으로, VM 내부 동작을 조사하고 분석하기 위한 디버깅 옵션을 사용할 수 있도록 합니다.
  2. -Xlog:gc+heap+coops=debug: 이 옵션은 가비지 컬렉션(GC), 힙(heap), 및 COOPs (Compressed Oops)와 관련된 디버그 레벨의 로깅을 활성화합니다. 이렇게 하면 GC 동작 및 메모리 할당에 대한 자세한 정보를 얻을 수 있습니다.
  3. Xmx31G: 이 옵션은 Java 프로세스의 최대 힙 크기를 31 기가바이트로 설정합니다. 이렇게 하면 애플리케이션이 사용할 수 있는 최대 힙 메모리 양을 제한합니다.

<결론>

  • zero-based 를 적용하는게 더 나은지 안 나은지 테스트하기 어려운 상황이면 속편하게 zero-based 적용 선까지 메모리 최댓값을 낮추자.
  • 최소 Compressed OOPs 는 까지는 적용되어야 한다.

서버 메모리가 128GB 이상이라면?

  1. keyword, log, date 등 doc_values 를 쓰는 타입에 대해 정렬, 집계가 많은 경우

→ 서버에 노드 1개만 32GB 로 띄워라. doc_values 는 파일 시스템 캐시를 많이 쓰니까 남는 메모리는 OS 가 쓰게 냅둔다.

  1. text 인 fielddata 타입에 대한 정렬, 집계가 많은 경우

fielddata 는 힙에 저장하니까 32GB 씩 2개 띄우는게 나을 수 있다.

=> 반드시 정답은 아니므로 성능 테스트 해보고 결정하자

 

스와핑은 완전히 끄는게 좋다

Disable swapping

스와핑하면 ms 단위로 끝날 GC 를 분단위 까지 걸리게 만드므로 쓰지 않도록 강력히 권고한다. 스와핑하느니 운영체제가 노드를 kill 시키게 놔두는 것이 낫다고 한다.

vm.max_map_count

최대 몇 개까지 메모리 맵 영역을 가질 수 있는지 설정하는 값이다. 최대치를 규정하는 값이라 매우 높게 설정하더라도 메모리 사용량이나 성능상 손해는 없다고 알려져 있다.

ES 기동하려면 262144보다 높은 값을 설정해야 한다.

💡 메모리 맵 이란?
작성된 코드를 실행파일로 만들어 os 에서 실행할 때 각 데이터 영역을 메모리의 어디 지역을 쓸 것인지 분류별로 나눠 매핑한 지도

https://www.gimsesu.me/elasticsearch-change-vm-max-map-count

File descriptor

File Descriptors

리눅스는 많은 파일을 다루기 때문에 최소 65534 이상으로 지정한다.

💡 파일 디스크립터 란?
파일을 관리하거나 접근할 때 쓰는 ID 같은 개념.
흔히 유닉스 시스템에서 모든 것을 파일이라고 한다. 일반적인 정규파일부터 디렉토리, 소켓, 파이프, 블록 디바이스, 케릭터 디바이스 등 모든 객체들을 파일로 관리한다.
유닉스 시스템에서 프로세스가 이 파일들을 접근할 때 파일 디스크립터라는 개념일 이용한다.

클러스터 구성 전략

마스터 후보 노드와 데이터 노드를 분리해야 하는 이유

① 만약 분리해 두지 않았다면..

  • 상대적으로 데이터 노드가 죽는 경우가 많은데, 마스터 역할까지 없어져 버리면 클러스터 안정성이 매우 떨어지고 전체 장애 상황으로 이어질 수 있다.

분리해뒀다면

  • 데이터노드가 죽으면 마스터노드가 레플리카를 프라이머리로 승격시키고 레플리카 새로 채우면서 클러스터 복구 했을 것이다. (=서비스 고가용성)

② 만약 분리해 두지 않았다면..

  • 장애상황에서 불필요하게 데이터 노드가 재시작 되는 경우 → 샤드복구 과정이 수행됨 → 부하가 더 심각하게 장애 상황을 몰아갈 수도 있다.
  • 장애상황에서 불필요하게 마스터 노드가 재시작 되는 경우 → 마스터 재선출 과정이 발생 → 네트워크나 GC 이슈 있으면 마스터를 잘 못찾을 수도 있다.

마스터 후보 노드 관리 가이드

-투표 구성원은 마스터 후보 노드의 일부 또는 전체로, 과반 이상 동의하면 마스터가 결정된다.

  • 그래서 투표 구성원이 절반 이상 다운되면 투표 못하는 상황에 빠짐!

-마스터 후보 노드가 새로 들어오거나 나갈 때 투표 구성원을 자동 조정하기 때문에 넣고 뺄땐 천천히 하는게 좋다.

-투표 개념이 도입된 ES 7 이상부터 split brain 이 원천적으로 일어나지 않는다. 그래도 홀수대 마스터 후보를 준비하는 게 좋다.

  • 과반 이상인 투표 형태 만들기 위해 어차피 하나는 투표 구성원에서 빼둠. 그래서 짝수로 하는게 노드가 하나씩 죽는 경우에는 스페어가 있으므로 안정성은 있지만 모두 한 번에 죽어버리면 소용 없으므로 홀수로 준비하는게 비용 대비 효용성이 좋다.

서버 자원이 많지 않을 때

적어도 마스터 후보 노드 3개, 데이터 노드 3개는 확보돼야 기본적인 고가용성이 제공된다.

최소 구성, 장비 3대

3대 모두 마스터 후보, 데이터 노드 겸임하는 방법밖에 없지 뭐

사양 낮은 장비 4~5대

3대: 마스터 후보, 데이터 노드 겸임

2대: 데이터 노드 전용

사양 높은 장비 4~5대

일단 같은 비용으로 사양 낮은 장비 3대랑 좀 더 높은 3~4대로 구성가능한지 알아보고

  • 되면 사양 낮은 3개를 마스터에게 주기
  • 안되면 똑같이 3대는 마스터, 데이터 노드 겸임하고 2대는 데이터 노드 전용

장비 6~7대

역할 분리 가능!

3대 마스터 후보 노드 전용, 나머지 데이터 노드 전용

서버 자원이 굉장히 많이 필요할 때

물리 서버가 200대 이상인 경우

-먼저 클러스터를 잘게 쪼갤 수 있는지 본다. 기본적으로 마스터는 클러스터 당 한 개이기 때문!

-그렇수 없다면 마스터 후보 노드 사양도 높은 서버로 준비한다. 그래도 언젠간 못 버티는 상황이 올 것.

-같은 데이터로 싱크 맞춘 클러스터를 여러 개 구성하고 로드 밸런싱 / 클러스터 별 샤딩 전략 / 클러스터 간 검색 도입 고려

사양이 크게 나는 서버일 때

데이터 티어 구조 도입 고려

  • 성능 좋은 건 data_content, data_hot 노드로, 낮은건 data_warm, data_cold, data_frozen 노드로
  • ILM 도입해 오래된 인덱스를 낮은 티어로 이동

하지만 단점도 있기 때문에 판단이 필요..!

  • 가장 아래 티어가 가장 낮은 서버인데 아량의 오래된 데이터를 들고 있는 상태에서 계속 복제 받아야 하는 상황이라 퍼포먼스 떨어지면 클러스터 전체 안정성에 영향 미칠 수 있다.
  • data_hot 노드 인덱스를 data_warm 으로 이동하는 작업에도 클러스터에 부하를 준다.

조정 전용 노드

-작업한 결과물을 모아서 돌려주는 작업은 생각보다 큰 부하 줄 수 있기 때문에 node.roles: [] 를 지정해 조정 전용 노드를 두는 것이 좋다.

-특히 키바나는 직관적인 UI 를 갖고 있기 때문에 ES 동작 이해도가 없는 상태에서 조작하다보면 부하가 큰 요청을 날려 장애 발생시킬 수 있다.

  • 키바나가 조정 전용 노드만 바라보게 설정하자

-읽기 담당 조정 노드와 쓰기 담당 조정 노드를 분리하는 것도 안정성을 높일 수 있다.

  • 장애 발생 시 쓰기는 멈추더라도 읽기는 계속 제공해야 한다면 쓰기 노드를 내리고 샤드 복구 기다리면 된다. 샤드 복구는 프라이머리 내용과 레플리카 내용 비교해서 필요한 작업만 재처리 해주는데 데이터 업데이트가 계속 늘어나면 데이터 간 차이가 벌어져 복구 속도가 느려지기 때문이다.
  • 반대로 쓰기 요청은 계속 받아야하는데 키바나 같은 거 때문에 과도한 읽기 요청이 온다면 읽기 노드만 내리면 된다.

-데이터 노드보다 낮은 사양으로 구성해도 되지만, 무거운 집계 작업이 주가 되는 클러스터면 좋은 사양으로 구성한다.

-ES 7부터 도입된 메모리 서킷 브레이커가, 조정 노드 메모리 사용량이 높아지면 차단해준다.

한 서버에 여러 프로세스 띄우기 가이드

-마스터 후보 노드는 여러 프로세스 대상으로 고려하지 않는다. 안정성이 크게 떨어지기 때문이다.

-여러 프로세스 대상은 데이터 노드여야 한다.

-cluster.name 은 같게, node.name, http/transport port, path.logs, path.data 는 다르게

-cluster.routing.allocation.same_shard.host: true 로 설정. 같은 샤드의 프라이머리와 레플리카가 한 서버에 몰리지 않게 조정해준다.

-기본적으로 ES 는 CPU 코어 개수로 스레드 풀 크기를 조정하기 때문에 [node.processors](https://www.elastic.co/guide/en/elasticsearch/reference/current/modules-threadpool.html#node.processors "https://www.elastic.co/guide/en/elasticsearch/reference/current/modules-threadpool.html#node.processors") 에서 수동으로 지정해준다. (ex. 16 코어면 8로 설정)

보안 기능 적용

xpack.security.enabled: true ES 8부터는 기본값 true로 변경됨

[[https 원리]] [[TLS (Transport Layer Security)]]

TLS 부트스트랩 체크

-노드 간 transport 통신에 TLS 적용하지 않으면 기동을 거부한다. (discovery.type:single-node 제외)

-근데 처음 보안 설정하려면 클러스터 기동한 상태에서 할 수 있다!?

→ 부트스트랩 우회해서 기동하고 설정하면됨!

이거 하나면 끝! 노드 추가나 키바나 기동할 때 한방에 되는 enrollment token 생성 및 사용하기

ES 8 ~

Start the Elastic Stack with security enabled automatically

Elasticsearch, Kibana, Beats, Logstash의 보안을 유지하기 위한 SSL, TLS, HTTPS 구성

enrollment 토큰 생성

클러스터 중 한 대 노드에 elasticsearch.yml 설정 후 데몬 말고 바로 기동

elasticsearch.yml

node.roles: [master, data]
discovery.type: "single-node"
...

-single-node: TLS 부트스트랩 회피 목적

-cluster.initial_master_nodes, xpack.security.enabled 는 추가하지 않는다.

콘솔에 출력된 enrollment 토큰 복붙해놓는다. 바로 종료해보면 certs 파일이 생기고 elasticsearch.yml 이 업데이트 되어 있을 것이다.끝.

enrollment 토큰으로 노드 추가하기

-elasticsearch.ymlcluster.initial_master_nodes, xpack.security.enabled , discovery.seed_hosts, discovery.type 는 추가하지 않는다.

-마스터 후보 노드 먼저 elasticsearch -d --enrollment-token ... 커맨드를 실행하면 자동으로 합류되고 elasticsearch.yml 이 업데이트된다.

초기 비번 설정

클러스터 노드 아무데나에서 아래 커맨드 실행해 초기 비번 설정한다.

elasticsearch-reset-password --interactive -u lastic

enrollment 토큰으로 키바나 연동하기

-kibana.ymlelasticsearch.hosts 는 지정하지 않는다.

-키바나 보안 연동하기

-연동 완료하면 kibana.yml 가 업데이트 된다.

※ 키바나와 브라우저 사이에 TLS 적용은 책 참고

※ 수동으로 TLS 적용하는 거도 책 참고

 

 

레퍼런스

엘라스틱서치 바이블 5장