검색어 Lucene에 대한 글을 관련성을 기준으로 정렬하여 표시합니다. 날짜순 정렬 모든 글 표시
검색어 Lucene에 대한 글을 관련성을 기준으로 정렬하여 표시합니다. 날짜순 정렬 모든 글 표시

[컴] elasticsearch 에서 JVM heap size 설정

 

elastic search heap size 결정 / 힙 사이즈 / 어느정도 크기로 / 메모리 확장 /

elasticsearch 에서 JVM heap size 설정

  • 총 메모리의 1/2 까지만
  • 그래도 최대치는 26GB ~ 30GB 이하면 된다.

Set the JVM heap size

기본적으로 Elasticsearch는 노드의 role(master, data 등) 및 총 메모리를 기반으로 JVM heap 크기를 자동으로 설정한다. 대부분의 프로덕션 환경에서는 기본 크기를 사용하는 것을 권장한다.

기본 heap 크기를 재정의하려면 최소 및 최대 힙 크기 설정(Xms 및 Xmx)을 설정하면 된다. 최소값(Xms)과 최대값(Xmx)은 같아야 한다.

heap 크기는 사용 가능한 RAM을 기준으로 해야 한다.

  • Xms 및 Xmx를 전체 메모리의 50% 이하로 설정한다. Elasticsearch에는 JVM heap 이외의 목적으로 메모리가 필요하다. 예를 들어 Elasticsearch는 효율적인 네트워크 통신을 위해 off-heap buffers를 사용하고 파일에 대한 효율적인 액세스를 위해 운영 체제의 파일 시스템 캐시에 의존한다. JVM 자체도 약간의 메모리가 필요하다. Elasticsearch는 Xmx 설정으로 구성된 제한보다 많은 메모리를 사용하는 것이 일반적이다.

    • off-heap buffers
    • 파일 시스템 캐시
    • JVM 자체가 사용하는 memory

    NOTE: Docker와 같은 컨테이너에서 실행되는 경우 총 메모리는 호스트의 “총 시스템 메모리”가 아니라 “컨테이너에 표시되는 메모리 양”으로 정의된다.

  • Xms 및 Xmx를 압축된 일반 개체 포인터(ordinary object pointers, oops)의 임계값(threshold) 이하로 설정한다. 정확한 임계값은 다양하지만 26GB는 대부분의 시스템에서 안전하며 일부 시스템에서는 30GB까지 정도 될 수 있다. 임계값 미만인지 확인하려면 Elastic search 로그에서 다음과 같은 항목을 확인하자.

heap size [1.9gb], compressed ordinary object pointers [true]

또는 노드 정보 API를 사용하여 노드에 대한 jvm.using_compressed_ordinary_object_pointers 값을 확인하자.

curl -X GET "localhost:9200/_nodes/_all/jvm?pretty"

Elasticsearch에 사용할 수 있는 heap이 많을수록 내부 캐시(internal cache)에 더 많은 메모리를 사용할 수 있다. 이렇게 하면 운영 체제가 파일 시스템 캐시(filesystem cache)에 사용할 메모리가 줄어듭니다. heap이 클수록 garbabe collection pause 들이 길어질 수도 있다.

heap size를 설정하려면 확장자가 .options인 사용자 지정 JVM 옵션 파일에 XmsXmx JVM 인수를 추가하고 jvm.options.d/ 디렉토리에 저장한다. 예를 들어 max heap size를 2GB로 설정하려면 Xms 및 Xmx를 모두 2g으로 설정한다.

-Xms2g
-Xmx2g

테스트를 할 때는, ES_JAVA_OPTS 환경 변수를 사용하여 heap size를 설정할 수도 있다.

ES_JAVA_OPTS="-Xms2g -Xmx2g" ./bin/elasticsearch

ES_JAVA_OPTS 변수는 다른 모든 JVM 옵션을 재정의(override) 한다. 운영에서는 ES_JAVA_OPTS 를 사용하지 않는 것이 좋다.

Heap: Sizing and Swapping

ref.2 의 내용은 오래된 버전의 내용이지만 알아둬야 할 내용들이 있다.

Give (less than) Half Your Memory to Lucene

일반적인 문제는 heap을 너무 크게 구성하는 것이다. 64GB의 컴퓨터를 사용하고 있다면, 놀랍게도 Elasticsearch에 64GB의 모든 메모리를 제공하려고 한다. 많을수록 좋다!

heap은 Elasticsearch에서 확실히 중요하다. 빠른 동작을 제공하기 위해 많은 in-memory data structure들에서 사용된다. 하지만 같은 맥락으로, memory의 또 다른 주요 사용자인 Lucene이 있다.

Lucene은 in-memory data sturcture를 caching하기 위해 OS를 활용하도록 설계되었다. Lucene segment는 개별 파일에 저장된다. segment는 immutable하므로 이러한 파일은 변경되지 않는다. 이것은 cache 를 사용하는데 아주 적합한 구조다. OS는 더 빠른 액세스를 위해 hot segement를 메모리에 상주시킨다. 이러한 segment들에는 inverted index(fulltext search 를 위한)과 doc values(aggregations의 경우)이 모두 포함된다.

Lucene의 성능은 OS와의 이 상호 작용에 달려있다. 하지만 Elasticsearch의 heap에 사용 가능한 모든 메모리를 준다면 Lucene에게 남은 메모리가 없게 된다. 이는 성능에 심각한 영향을 미칠 수 있다.

표준 권장 사항은 사용 가능한 메모리의 50%를 Elasticsearch heap에 할당하고 나머지 50%는 사용 가능한 상태로 두는 것이다. Lucene 이 남은 메모리를 사용할 것이다.

분석된 문자열 필드를 aggregate하지 않는 경우(예: 필드 데이터가 필요하지 않음) heap을 더 낮추는 것을 고려할 수 있다. heap을 작게 만들수록 Elasticsearch(더 빠른 GC)와 Lucene(캐싱을 위한 더 많은 메모리) 모두에서 더 나은 성능을 기대할 수 있다.

Don’t Cross 32 GB!

Elastic search에 엄청난 heap을 할당하지 않는 또 다른 이유가 있다. HotSpot JVM은 heap이 약 32GB 미만일 때 객체 포인터(object pointer)를 압축하는 트릭을 사용한다.

자바에서 모든 object들은 heap에 할당되고 포인터에 의해 참조된다. 일반 객체 포인터(Ordinary object pointers, OOP)는 이러한 object를 가리키며, 전통적으로 프로세서의 cpu의 native word size 이다.(32비트 또는 64비트, cpu에 따라 다르다). 포인터는 값의 정확한 byte location를 reference 한다.

32비트 시스템의 경우 최대 heap 크기는 4GB입니다. 64비트 시스템의 경우 heap 크기가 훨씬 커질 수 있지만 64비트 포인터의 오버헤드는 포인터가 더 크기 때문에 낭비되는 공간이 더 많다는 것을 의미한다. 그리고 낭비되는 공간보다 더 나쁜 것은, 큰 포인터들이 메인 메모리와 다양한 캐시들(LLC, L1 등) 사이에서 값을 이동할 때 더 많은 대역폭을 소비한다는 것이다.

자바는 이 문제를 피하기 위해 compressed oops 라고 불리는 트릭을 사용한다. 포인터들은 메모리에서 정확한 바이트 위치를 가리키는 대신 object offset 들을 참조한다. 이것은 32비트 포인터가 메모리에 있는 exact byte location 40억 바이트가 아닌 40억 개의 객체를 참조할 수 있다는 것을 의미한다. 궁극적으로, 이는 heap이 한계치가 4GB 인 32비트 포인터를 사용하면서도 메모리가 32GB로 증가할 수 있음을 의미한다.

마법의 ~32GB 경계를 넘으면 포인터가 다시 일반 개체 포인터(ordinary object pointers)로 전환된다. 각 포인터의 크기가 커지고 더 많은 CPU 메모리 대역폭이 사용되며 사실상 메모리가 손실된다. 실제로 할당된 heap의 유효 메모리가 약 40-50GB가 되어야 compressed oops을 사용하여 32GB 미만의 heap을 사용할 수 있다.

이 이야기의 교훈은 다음과 같다. 메모리가 남아있을 때에도 32GB heap 경계를 넘지 않도록 해야한다. 그것은 메모리를 낭비하고 CPU 성능을 떨어뜨리며 큰 heap 로 인해 GC 를 오래걸리게 한다.

See Also

  1. Compressed OOPs in the JVM | Baeldung

Reference

  1. Advanced configuration | Elasticsearch Guide [master] | Elastic
  2. Heap: Sizing and Swapping | Elasticsearch: The Definitive Guide [2.x] | Elastic

[컴][웹] ElasticSearch Mapping

ElasticSearch 의 mapping 에 대해 알아보자. 이 글은 대부분 아래글의 내용의 번역이 될 것이다.

일단 기본적으로 SQL DB 에 대한 지식이 있다는 전제로 이야기를 해 나가겠다.

schema? mapping?

elasticsearch 의 schema 는 json 형태로 되어 있다. 이 json 에 field 의 data type 이나, 어떤 식으로 Lucene index 안에서 어떻게 index 될 것인지 를 적어놓게 된다. 이런 이유로 elasticsearch 에서는 이 schema 를 mapping 이라고 부른다.

index, type, document

index 는 여러개의 type 을 갖을 수 있고, 1개의 type 은 여러개의 document 를 가질 수 있다. 물론 1개의 값을 가질 수도 있다.

index > type > document

index 를 SQL DB 의 database, type 을 table, document 를 record 로 보면 될 것이다. 아래글에 따르면, 처음 eleasticsearch 가 index 를 rdbms 의 database 와 같다고 했지만 그것이 mapping type 의 field 에 대해서는 틀린 가정을 가져온다고 한다. 그리고 see also. 2 를 확인하면, type 이라는 존재가 사라졌다. 그래서 이제 index 는 table 로 개념을 가져가는 듯 하다.

default mapping

ElasticSearch 는 기본적으로 mapping 이 없이도 알아서 indexing 을 해준다. indexing 을 하는 동안에 새로운 field 를 만날 때 dynamically 하게 index 를 만들어 준다.

버전 7.0.0 이후로는 __default__ mapping 이 사라졌다고 한다.(deprecated)

default mapping 을 없애고 대신 document type 마다 index 를 만들던지, 새로운 type 을 만들어서 그 안에서 2개의 type 을 하나로 묶고, 그것을 구별할 custom type field 를 가져가던지 하라고 한다.(참고)

단점

단점은

  • Detected type 이 정확하지 않을 수 있다.
  • 원하지 않는 data 복사가 생길 수 있다.(특히, _source , _all field)
  • indexing 과 searching 에 default analyzer 와 세팅을 사용한다.

mapping 을 사용하는 방법

index 생성시 사용

가장일반적인 방법이다

curl -XPOST ...:9200/my_index -d '{
    "settings" : {
        # .. index settings
    },
    "mappings" : {
        "my_type" : {
            # mapping for my_type
        }
    }
}'

Put Mapping API 사용

이녀석을 사용할 때는 mapping 되는 index 가 중복되는 경우에 mapping 이 update 되지 않을 수도 있고, ingnore_conflicts = true 로 한 경우라도, 이미 만들어진 index 가 새롭게 update 된 mapping 에 따라 update 되지 않을 수도 있다. 그래서 대부분의 경우는 index 생성시에 mapping 을 사용하는 방법을 이용하라고 한다.

$ curl -XPUT 'http://localhost:9200/my_index/my_type/_mapping' -d '
{
    "my_type" : {
        # mapping for my_type
    }
}

index의 mapping 정보 확인

elasticsearch-sql-cli.bat

<elasticsearch_root>/bin/elasticsearch-sql-cli.bat 를 실행하면, sql 로 elasticsearch 를 retrieve 할 수 있게 해준다. 일단 안되는 명령어는 error 가 나온다.

show tables;
select * from ".elatichq"

mapping 정보와 elasticsearch-sql-cli의 결과 비교

elasticsearch-sql-cli.bat 를 사용하면 아래처럼 mapping 정보를 확인할 수 있다. mapping 은 간략하게 이야기하면 RDBMS 의 schema 와 같은 역할을 한다고 보면 될 듯 하다.

sql> select * from ".elastichq";
    doc_id     |   doc_type    |historic_days_to_store|historic_poll_interval|  index_name   |show_dot_indices| store_metrics |    version    |websocket_interval
---------------+---------------+----------------------+----------------------+---------------+----------------+---------------+---------------+------------------
hqsettings     |data           |7                     |300                   |.elastichq     |true            |true           |1              |5


// curl localhost:9200/.elastichq?pretty=true
{
  ".elastichq" : {
    "aliases" : { },
    "mappings" : {
      "properties" : {
        "doc_id" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "doc_type" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "historic_days_to_store" : {
          "type" : "long"
        },
        "historic_poll_interval" : {
          "type" : "long"
        },
        "index_name" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "show_dot_indices" : {
          "type" : "boolean"
        },
        "store_metrics" : {
          "type" : "boolean"
        },
        "version" : {
          "type" : "long"
        },
        "websocket_interval" : {
          "type" : "long"
        }
      }
    },
    "settings" : {
      "index" : {
        "routing" : {
          "allocation" : {
            "include" : {
              "_tier_preference" : "data_content"
            }
          }
        },
        "number_of_shards" : "1",
        "provided_name" : ".elastichq",
        "creation_date" : "1619967012964",
        "number_of_replicas" : "1",
        "uuid" : "gS2CCpcSSHGLmTRvqbetoQ",
        "version" : {
          "created" : "7120199"
        }
      }
    }
  }
}

See Also

  1. A Data Exploration Workflow for Mappings
  2. 쿠...sal: [컴] ElasticSearch 에서 Type 이 사라졌다
  3. 쿠...sal: [컴] elasticsearch 에서 curl 을 이용해서 data 옮기기