본문 바로가기
ELK Stack

[Elasticsearch] 엘라스틱서치 메모리(1) - 왜 32GB보다 낮게 설정해야하는가? (Compressed OOP)

by 잭피 2022. 12. 23.

안녕하세요~ 잭피입니다!

오늘은 Elasticsearch jvm memory 및 Compressed OOP와 관련된 내용을 포스팅하려고 합니다!


엘라스틱서치 공식문서

먼저 공식문서에서 가이드하고 있는 정보를 확인해보겠습니다.

 

https://www.elastic.co/guide/en/elasticsearch/reference/7.17/advanced-configuration.html

 

Advanced configuration | Elasticsearch Guide [7.17] | Elastic

When running in a container, such as Docker, total memory is defined as the amount of memory visible to the container, not the total system memory on the host.

www.elastic.co

힙사이즈 임계값은 다양하지만 
대부분의 시스템에서 26GB가 안전하며 일부 시스템에서는 최대 30GB가 될 수 있다고 합니다.

 

그렇다면 Compressed Ordinary object pointers는 무엇을 의미하는 것일까요?

먼저 Ordinary object pointers가 무엇을 의미하는지 알아보겠습니다

 

Ordinary object pointers?

엘라스틱서치 메모리를 설정하여 실행할 때, 32GB를 기준으로 한 가지 차이점을 볼 수 있습니다.

한번 30GB일 때와, 32GB를 나누어 실행하고 로그를 봐볼까요?

엘라스틱서치 30GB

[elasticsearch] heap size [30gb], compressed ordinary object pointers [true]

엘라스틱서치 32GB

[elasticsearch] heap size [32gb], compressed ordinary object pointers [false]

차이점은 compressed ordinary object pointers 입니다.

 

먼저, Ordinary Object Pointer를 살펴보겠습니다. 

Ordinary Object Pointer(OOP)는 JVM 메모리 상의 주소를 저장하는 구조체입니다.

 

OOP는 시스템에 따라 32bit 또는 64bit 기반의 크기를 가집니다

 

32bit의 경우, 2의 32제곱으로 대략 최대 4GB까지의 주소 공간을 가리킬 수 있습니다

 

64bit의 경우, 2의 64제곱으로 

18EB (1EB(Exa byte, 엑사바이트) = 2^10 x 1PB = 1024PB)

이론상 대략 18,446,743,073GB까지 주소 공간을 가리킬 수 있습니다.

 

현실적으로 18EB까지 메모리를 사용할 수 없고, 64bit 포인터로 공간을 관리할 경우 문제가 발생합니다

 

CPU상 레지스터는 64bit로 동작하며,

1개의 CPU 명령어를 처리하는데 필요한 레지스터 연산은 32bit보다 2배의 주소공간이 필요하고 Cache Hit rate도 감소합니다

 

또한, 객체의 field, metadata의 크기가 32bit와 64bit간 차이가 있습니다

같은 객체를 메모리에 할당하더라도 32bit보다 64bit에서 사용량이 큽니다

 

따라서 64bit 포인터로 공간을 관리하는 것은 효율적이지 않습니다

 

하지만 32bit 포인터로 4GB까지만 나타내기엔 용량이 작습니다

JVM은 이러한 문제를 해결하기 위해 64bit JVM에서 32bit 포인터를 이용하는 것과 유사하게 

최대 힙 크기를 32GB까지 사용할 수 있도록 Compressed OOP를 지원합니다 

 

Compressed OOP(Ordinary object pointers)

32bit 만으로도 32GB 힙을 사용할 수 있도록 지원하는 방식을 Compressed OOP라고 합니다

 

기존 OOP는 4GB의 메모리 영역을 직접 관리합니다

하지만, Compressed OOP는 64bit 포인터를 32bit Object Offset으로 인코딩 & 디코딩하여 32bit 포인터를 사용하는 것 처럼 지원합니다.

즉,  Compressed OOP는 Object 주소를 직접 참조하지 않고 Object 주소의 Offset을 참조합니다

 

그 Offset은 8의 n 배수로 계산되는데,

1이면 8번 주소,

2이면 16번 주소,

...

10이면 80번 주소를 참조합니다

이런 방식을 통해 기존보다 8배 더 많은 주소 공간을 표시할 수 있습니다

 

따라서 표현할 수 있는 주소의 영역이 8배 많은 32GB가 됩니다

 

Compressed OOP의 경우 8의 배수 단위로 Object를 저장하기 때문에

실제 메모리 주소를 참조하기 위해서 left shift 연산이 필요합니다 

이 연산은 CPU 사용이 크지 않아 주소 변환에 성능 저하는 없습니다 

native oop = (compressed oop << 3)

 

다만 64bit JVM을 사용할 때 힙 사이즈가 32GB이상이면 이 Compressed OOP를 이용하지 않고 자동으로 64bit OOP를 사용합니다.

 

따라서 32GB보다 작은 메모리를 설정해야 합니다.

 

그 임계치는 아래와 같은 방식을 통해 확인할 수 있습니다

시스템마다 임계치가 다르므로 숫자를 바꾸어가며 확인해봅니다.

 

# java -Xmx32769m -XX:+PrintFlagsFinal 2> /dev/null | grep UseCompressedOops
bool UseCompressedOops  := true

# java -Xmx32770m -XX:+PrintFlagsFinal 2> /dev/null | grep UseCompressedOops
bool UseCompressedOops  := false

 

글쓴이는 적당하게 30GB로 설정하여 사용하고 있습니다.

 

 Zero Based Compressed OOP(Ordinary object pointers)

JVM은 실행될 때, OS로부터 힙 영역을 할당 받습니다

이 때, 주소 공간이 0부터 시작하는 힙 메모리를 요청하여 Compressed OOP를 사용하는 경우를

Zero based Compressed OOP라고 합니다

 

Zero based가 아닌 경우, base 주소로부터 실제 오브젝트 주소를 찾기 위해 더하기 연산이 필요합니다

하지만, Zero based의 경우 base 주소를 더하는 연산이 필요없고, shift 연산만으로 주소를 구할 수 있습니다.

 

Zero based로 할당받을 수 있는 임계치는 아래와 같이 확인할 수 있습니다

(JAVA_OPTS에 아래 항목을 넣어서 ES를 실행)

 

-XX:+UnlockDiagnosticVMOptions -XX:+PrintCompressedOopsMode

 

만약 Zero Based라면,

Compressed Oops mode: Zero Based 라는 문구를 볼 수 있습니다.

 

 

 

정리

엘라스틱서치 메모리를 32GB보다 아래로 설정하여 사용하자

 

 

추가로 엘라스틱서치 서버의 경우 전체 메모리의 50%는 남겨두어야 합니다.

해당 내용이 궁금하신 분은 아래 포스팅을 읽어주세요~

 

2022.12.26 - [ELK Stack] - [Elasticsearch] 엘라스틱서치 메모리(2) - 왜 전체 시스템 메모리의 50%를 남겨두어야 하는가?

 

[Elasticsearch] 엘라스틱서치 메모리(2) - 왜 전체 시스템 메모리의 50%를 남겨두어야 하는가?

안녕하세요~ 잭피입니다! 오늘은 Elasticsearch를 실행시킬 때, 전체 메모리의 50%를 남겨두어야 하는 이유를 알아보겠습니다 엘라스틱서치 공식문서 먼저 엘라스틱서치 공식문서를 살펴볼까요? 공

jackjeong.tistory.com

 

댓글