elasticsearch 는 워낙 유명하고 안정적으로 성장한 오픈소스라 공식 문서, 커뮤니티, 블로그, 소스코드 등 참고할 자료들이 넘쳐난다. 굳이 그 넘쳐나는 자료에 한 숟가락을 더 얹을 필요가 있겠냐마는, 프로덕션 환경에 elasticsearch 를 처음 도입하려는 사람에게 찾는 수고를 덜 수 있는 best practice 를 제공하는 것이 이 문서의 목적이므로 누군가에게는 도움이 될 것으로 생각한다. elk 스택이나 관리용 플러그인, 키바나 사용법 등은 필자가 잘 모르기도 하고 워낙 좋은 문서가 많기 때문에 다른 문서를 참조하는 편이 낫다. 이 문서는 elasticsearch cluster 를 구성할 때 참고할 만한 사항들을 정리하였다.

ECK(Elastic Cloud on k8s)

ECK는 k8s 에 거부감이 없다면 elasticsearch 운영환경으로 선택할 수 있는 좋은 옵션으로, elasticsearch 개발사인 Elastic 에서 공식 배포하는 k8s operator pattern 이다. k8s 환경에 빠르게 적용할 수 있으며, elasticsearch 특성을 고려한 리소스 / lifecycle 관리가 가능하다.

Operator pattern이란?

k8s에서 기본 제공하는 방식으로 서비스 운영하기엔 도메인 특성이 적합하지 않아 반복적인 설정/변경작업이 잦을 경우 직접 custom resource 를 작성할 수 있는데, 이 custom resource 를 관리하는 확장 인터페이스가 operator 이며, 이렇게 custom resource 와 opertor를 제작하여 k8s 를 사용하는 패턴을 operator pattern 이라 한다.

elasticsearch 적정 메모리

elasticsearch 는 메모리의 크기가 매우 중요하다. 다큐먼트로부터 인덱스를 생성할 때에도 메모리를 사용하고, 검색 속도 향상을 위한 캐시에도 메모리를 사용하기 때문에 elasticsearch 가 빠른 성능을 내기 위해선 메모리 리소스가 넉넉해야 한다. 그럼 그 넉넉한 메모리의 적정 규모는 얼마일까?

jvm compressed oop

대부분 elasticsearch 와 적정 메모리 관련 문서를 찾아보면 jvm heap 에 32Gbytes 이상 할당하지 말라는 내용이 많을 것이다. compressed oop 라는 기능으로 메모리를 효율적으로 쓸 수 있는 최대치가 32Gbytes 이기 때문이다. 절반은 맞고 절반은 틀렸다.

Compressed OOPs in the JVM | Baeldung
compressed oop란 0으로 padding 되어 실질적으로 사용하지 않는 주소 영역 3bit 도 addressing 에 활용하는 기술이다. 2^3 만큼 이득이므로 32bit(=4G) x 8 = 32Gbytes 까지 addressing 이 가능하다.

64bit 주소를 사용하면 메모리 공간 내에서 데이터 저장영역이 그만큼 줄어들기 때문에 효율성 측면에서 heap size는 32Gbytes를 넘지 않는 편이 좋았다. 과거에는 말이다.

zgc

zgc는 java11 부터 사용할 수 있는 신규 gc 이다. 벤치마크를 확인해 보면 성능이 매우 뛰어남을 알 수 있다. 허나 zgc를 사용하려면 compressed oop 를 쓰면 안된다. 0으로 채워지는 padding 영역을 zgc에서 사용하기 때문이다.

64bit 주소체계에서 18bit 는 사용되지 않는다. zgc는 저 사용되지 않는 공간을 활용하여 gc 의 성능을 높였다. 기회가 되면 zgc에 대해 따로 다뤄보겠다.
gc 벤치마크이다. zgc의 성능이 매우 높음을 알 수 있다. 또한 gc 에서 발생하는 latency 가 낮기 때문에 체감 성능은 기존 mark&sweep 이나 g1gc보다 월등히 높을 것으로 보인다.

compressed oop 는 32Gbytes 제약이 있으나 32bit 주소체계이기 때문에 메모리 공간을 효율적으로 사용할 수 있다. 반면 zgc는 64bit 주소체계이기 때문에 메모리 공간 사용률이 효율적이지 않지만 gc 성능이 빠르다. 그럼 둘 중에 어느 것이 효율적일까? 정해진 답은 없으나 heap size 가 32Gbytes 이하라면 compressed oop, 그 이상으로 heap을 크게 써야 한다면 zgc를 사용하는 편이 이득일 것으로 보인다.

lucene mmaped io

elasticsearch에 메모리를 할당할 때 주의할 점이 하나 더 있는데, 서버의 모든 메모리 리소스를 jvm에 할당하면 오히려 성능상 불리해질 수 있다. lucene은 memory mapped io 를 사용하는데, virtual memory 의 원활한 paging 을 위해 시스템 영역에 충분한 메모리를 남겨두어야 한다.

The Generics Policeman Blog: Use Lucene's MMapDirectory on 64bit ...
lucene 의 MMapDirectory 는 virtual memory를 사용하는데, virtual memory 의 성능을 위해서 시스템 영역에 충분히 메모리를 남겨둘 필요가 있다.

Maximum shards in node

elasticsearch 를 default 설정으로 사용하였을 때, index 하나 당 shard 갯수는 5개, node 당 maximum shard 갯수는 1000개이다. 필자는 이걸 모르고 index를 많이 만들었다가 shard 갯수가 1000 개를 초과하여 더이상 index를 생성하지 못하는 문제를 겪었다. node 당 shard 갯수는 설정으로 조절이 가능하므로 shard 를 늘리고 싶다면 클러스터 설정을 바꾸면 된다.

그렇다면 node 하나 당 적절한 shard 갯수는 얼마일까? elasticsearch 공식 블로그에 따르면 적절한 heap 1Gbyte 당 shard 20개가 적절하다고 하니 참고하길 바란다. (https://www.elastic.co/kr/blog/how-many-shards-should-i-have-in-my-elasticsearch-cluster)

Hot-Warm architecture

elasticsearch 는 저장 비용이 큰 편이다. 주어진 리소스가 데이터 양에 비해 충분히 넉넉하다면 별 문제가 없겠으나, 리소스를 효율적으로 사용하려면 아키텍처를 적절히 구성하여야 할 것이다. 일반적으로 최근 데이터는 검색을 자주하는 반면 오래된 데이터는 그렇지 않은 경우가 많은데, hot-warm 모델은 index 를 고성능 data node(hot) -> 저성능 data node(warm) -> 삭제 의 순서로 이동시키며 lifecycle을 관리하는 아키텍처이다.

hot-warm_cluster.png
Hot node 는 고성능의 저장장치와 높은 메모리로 구성, 빈번한 읽기/쓰기 작업을 감당할 수 있도록 한다. 최초에 Hot node에서 생성한 index는 일정 시간이 경과하면 Warm node 로 이동시킨다. Warm node 는 고용량의 저가 저장장치로 구성, 참조 빈도가 낮은 데이터를 보관하는 용도로 사용한다.

opendistro ISM

opendistro의 ISM(Index State Management) 기능을 사용하면 Hot-Warm architecture 의 index lifecycle 을 쉽게 관리할 수 있다. opendistro에는 다른 여러 부가기능들이 있으므로 관심있으면 공식 문서를 참조 바란다.

“elasticsearch 구성 참고사항”에 대한 2개의 응답

  1. 좋을 글 감사합니다. 많은 도움이 되었습니다.

    1. 부족한 글 읽어주셔서 감사합니다.

댓글 남기기

인기 검색어

01010011에서 더 알아보기

지금 구독하여 계속 읽고 전체 아카이브에 액세스하세요.

Continue reading