Elasticsearch
는 메모리를 많이 사용하는 애플리케이션이다.
일반적으로 힙 메모리가 많을수록 그에 비례해서 성능도 올라간다. 🚀
OOM 오류(Out of Memory Exception)
를 발생시킬 수 있다.FullGC
가 발생할 때 STW(Stop the world)
시간이 길수도 있다.Elasticsearch에서 힙 크기를 얼마로 설정하면 좋을지 알아보자.
Elasticsearch Shard는 내부에 루씬(Lucene)
을 가지고 있다.
커널 시스템 캐시
를 최대한 많이 활용하고 있다.실시간 검색을 지원하기 위해서는 루씬이 최대한 많은 시스템 캐시를 확보하도록 지원해야 한다.
따라서 물리적인 메모리 공간의 50%
정도는 OS가 자유롭게 사용하도록 할당해야 한다.
같이 보면 좋아요. Elasticsearch 캐싱 심층 분석: 한 번에 하나의 캐시로 쿼리 속도 향상
Object Pointer
는 객체의 메모리 번지를 표현하는 주솟값이다.
힙에 생성된 모든 객체는 이러한 주솟값을 이용해 접근하게 된다.
JVM이 기본적으로 32비트 Object Pointer를 사용하고 있기 때문에 32비트 JVM과 64비트 JVM 모두 32비트 주솟값을 가지고 동작한다.
자바에서는 모든 객체가 힙 영역에 생성되고 생성된 객체는 모두 포인터(Pointer)를 가지고 있고 이 포인터를 이용해 객체에 접근한다.
JVM은 힙 영역에 생성된 객체에 접근하기 위해 포인터의 주소를 Ordinary Object Pointer(OOP)
라고 하는 특수한 자료구조로 만들어서 관리하고 있다.
32비트 시스템
- 까지 표현: 최대 4GB까지의 주소 공간을 가리킬 수 있다.
64비트 시스템
- 까지 표현: 이론상 18EB까지의 주소 공간을 가리킬 수 있다.
64비트 시스템의 경우 메모리상의 주소를 가리키는 포인터 1개를 64비트로 표현하다 보니 많은 메모리 공간의 낭비가 발생한다.
LLc
, L1
, L2
)가 있으며 캐시 적중률을 높이기 위해 주메모리와 캐시 사이에서는 지속적으로 값의 이동이 일어남
시스템의 패러다임이 32비트 시스템에서 64비트 시스템으로 변화하면서 많은 물리적인 한계를 극복할 수 있었지만 메모리 공간의 낭비나 연산 속도 저하 등의 단점도 함께 나타났다.
✅ JVM에서도 OOP를 위해 낭비되는 메모리 문제를 해결하기 위해 Compressed OOP
라는 새로운 개념의 포인터 관리 기법을 도입했다.
Compressed OOP
는 포인터의 공간 낭비를 줄이고 좀 더 빠른 연산을 위해 포인터를 압축해서 표현하는 일종의 트릭
이라고 할 수 있다.
상대적인 오브젝트 오프셋(Object Offset)을 가리키도록 살짝 변경해서 동작시키는 것
이다.8비트 포인터를 이용해 이 트릭을 사용한다면
256바이트의 물리적인 주소 공간을 표현하는 것이 아니라
256개의 객체
를 가리킬 수 있게 된다.
자바는 데이터 타입에 따라 객체를 8비트(boolean)부터 64비트(Long)까지의 8의 배수 형태로 힙 메모리에 생성한다.
Compressed OOP
를 이용해 포인터가 객체를 가리키게 한다면 32비트만을 이용해도 포인터가 최대 32GB까지의 힙 메모리 공간을 가리키는 것이 가능해진다.32비트 Compressed OOP
까지의 객체(Object)를 가리킬 수 있다.
객체의 최소 단위는 8비트이기 때문에 () * 8 까지의 메모리 공간을 가리킬 수 있다. (32GB)
Compressed OOP
를 자세히 알고 싶다면 이 글을 읽어보자
Compressed OOP
를 사용할 경우 포인터를 표현할 때 예외적으로 32비트 포인터를 사용해 동작한다.
🔥 32비트 포인터를 이용하면서도 64비트가 가지는 메모리 낭비 등의 단점을 우회해서 동작할 수 있는 것이다.
하지만 이러한 트릭은 힙 크기가 32GB
를 넘어가면 더는 사용할 수 없다.
JVM은 힙 크기가 32GB를 넘어가는 순간 Compressed OOP
를 일반적인 64비트 OOP로 자동으로 변환한다. 😱
👉 그래서 Elasticsearch
에서는 힙 크기를 설정할 때 최대 32GB 이하로만 설정하라고 안내하는 것이다.
아래 JVM 옵션으로 Compressed OOP를 사용할 수 있다.
jvm.options
-XX:+UseCompressedOops
최신 JDK에서는 Compressed OOP가 기본 설정으로 동작하기 때문에 힙 크기를 32GB 이하로 설정하기만 하면 된다.