[Elasticsearch] - Elasticsearch의 각 노드 별 적정 메모리 할당
Elasticsearch의 램 부족 현상
엘라스틱 서치를 멀티 노드 클러스터 환경에서 연습하던 중, 노드가 error code 137과 함께 죽는 현상이 종종 발생했습니다.
이는 메모리 부족과 관련된 이슈였는데, 사용 중인 랩탑의 총 메모리가 8GB에 불과해 노드 3개짜리 클러스터를 도커 컨테이너로 구성할 때
각 노드에 단 1GB씩을 할당해줘서 발생한 것이었습니다.
(기존 아키텍쳐 그림입니다)
엘라스틱 서치를 사용할 때는 연습환경일지라도 한 노드 당 최소 4GB 이상씩을 할당해줘야하고, 물론 빠른 작업을 제공하기 위해서는 메모리는 많으면 많을 수록 좋습니다.
만약 메모리가 남는다면, 특히 인덱싱과 CRUD, 검색 및 집계 등을 처리하는 데이터 노드에 더 많은 메모리를 할당해주는 것이 일반적으로 좋습니다.
이는 자신의 데이터의 특성에 따라 적절히 분배해주어야 합니다.
그러나 필자가 만든 실습환경 처럼 한 컴퓨팅 자원을 VM으로 쪼개서 마스터 노드, 데이터 노드, 인제스트 노드 등 역할을 나눠주는 것은
무의미함을 넘어 손해로 이어집니다.
역할을 할당하지 않는다면 해당 노드는 모든 노드의 역할을 맡게 되는데, 컴퓨팅 자원의 램이 64GB를 넘는 클라우드급 자원이 아니라면,
굳이 노드의 역할을 나눠 오버헤드를 발생시키는 것은 바람직하지 않기 때문입니다.
그렇다면 왜 램이 64GB를 넘을 때에만 노드를 나눠서 사용해도 괜찮다는 걸까요?
그것은 엘라스틱 서치에서 노드를 생성할 때의 다음 두가지 원칙 때문입니다.
1. 엘라스틱 서치에는 컴퓨팅 자원 전체 메모리의 50% 이상을 할당하지 않는다.
2. 한 노드에는 32GB 이상의 메모리를 할당하지 않는다.
첫 번째 원칙의 이유는 바로 "루씬" 때문입니다.
루씬(Lucene)은 엘라스틱 서치의 검색 엔진의 기반입니다.
그리고 루씬은 힙 메모리를 사용하지 않습니다.
그 말은, 루씬은 인메모리 데이터 구조를 캐싱하기 위해 기본 OS를 활용하고, 매우 캐시 친화적이며 기본 OS는 더 빠른 액세스를 위해 핫 세그먼트를 메모리에 상주시킵니다.
그리고 루씬의 성능은 이러한 OS와의 상호 작용에 의존하고, 만약 엘라스틱 서치의 힙에 많은 메모리를 제공할수록 루씬이 가용 가능한 메모리는 적어지게 됩니다.
그리고 이는 심각한 성능 저하로 이어지죠.
두 번째 원칙의 이유는 엘라스틱 서치 자바로 구성되었기 때문입니다.
자바 기반의 애플리케이션은 힙 사이즈에 비례해 성능이 좋아지지 않습니다.
그렇다면 자바로 구성한 것과 하필 32GB 이상의 메모리를 할당하지 않는 것은 무슨 연관이 있을까요?
그 이유는 JVM이 Object의 reference를 관리하기 위해 OOP(Ordinary Object pointer)라는 자료구조를 가지기 때문입니다. 그리고 Object의 field, metadata의 크기는 32bit와 64bit간 차이가 있어 같은 객체를 메모리에 할당하더라도 64bit JVM은 사용량이 더 큽니다.
따라서 JVM은 Compressed Ordinary Object Pointer를 채용하게 됩니다.
Compressed Ordinary Object Pointer란?
Compressed Ordinary Object Pointer는 64bit 포인터를 32bit object offset으로 인코딩 및 디코딩하여 32bit 포인터를 사용하는 것처럼 지원하고, 이를 통해 64bit JVM에서도 32GB까지의 Heap Size에서는 32bit 포인터의 이점을 살릴 수 있게 지원합니다.
이로 인해 메모리가 32GB를 넘어가면 그 이점을 살릴 수 없을 뿐더러, 오히려 CPU 성능을 저하시키며 GC가 큰 힙을 처리하는 데 어려움을 겪게 됩니다.
결론
즉 엘라스틱 서치 클러스터를 구성할 때는 몇 가지 방법이 있습니다.
한 서버(컴퓨팅 자원) 당 4GB 이상 32GB이하의 램을 할당한 하나의 노드만을 운용하거나,
더 나은 컴퓨팅 자원을 사용하여 여러 개의 VM(노드)를 만들거나 등등..
저는 후자를 선택하였고, 현재는 1.5TB 메모리를 가진 HCI 클러스터에 32GB 메모리를 할당한 VM 3개를 생성해 엘라스틱서치 클러스터를 만들어 실습용으로서 사용중입니다.
그리고 각 VM의 도커 컨테이너에는 그 절반인 16GB의 메모리를 할당해주었습니다.
(수정된 아키텍처 그림입니다)
++
그러나 해당 방식 또한 VM과 도커 컨테이너를 통한 이중 가상화이기 때문에 이 또한 불필요한 오버헤드가 발생합니다.
따라서 다음번 클러스터를 구축할 일이 생긴다면 VM위에 앤서블을 사용한 설치 스크립트를 제작할 예정입니다.
reference