====== Elastic Search ======
* [[search:elasticsearch:query|ElasticSearch Query]]
* http://www.elasticsearch.org/ : built on top of Apache Lucene
* [[https://aws.amazon.com/ko/elasticsearch-service/|Amazon Elasticsearch Service]]
===== 최대 색인 수 =====
* Shard 한개(Lucene 인덱스 하나)는 최대 21억건 문서, 2740억건의 고유 term까지만 허용한다.
* 따라서 데이터 증강량을 판별하여 이에 맞게 Sharding 수준을 정해야한다.
===== 노드 구성 =====
* ''node.data=true/false'' : 실제 색인을 가지고 있는 데이터 노드가 될 수 있는지 여부
* ''node.master=true/false'' : 마스터 노드가 될 수 있는지 여부
* ''node.data=false, node.master=false'' 인 검색 클라이언트 전용노드를 만들어서, 검색 요청을 여기서 받은 뒤에 데이터 노드에 검색을 요청하는 것이 가능하다. 이렇게 하면 실제 색인을 가진 데이터 노드는 클라이언트로부터의 socket 연결을 위한 오버헤드와 메모리 사용량을 줄일 수 있게 된다.
===== Sharding Routing =====
* 만약 Search 를 명확히 특정 Shard 단위로 할 수 있다면 샤딩을 촘촘히 해도 읽기/쓰기 성능이 모두 좋지만
* Sharding 기준이 명확하지 않아서 여러 Shard 에 걸쳐 Search 를 해야한다면, Shard 를 늘릴 수록
* 읽기 성능은 저하된다.
* Write Primary 노드는 여러개로 분산 되므로 Write 성능은 높아진다.
==== Routing 강제 ====
라우팅을 강제할 수 있다. 라우팅 옵션 없이는 인덱싱 불가.
"mappings": {
"[indexname]": {
"_routing": {
"required": true
}
}
}
===== Cluster 관리 =====
* ''host:9200/_cluster/settings?pretty'' : Cluster 상태 조회
* ''host:9200/_cluster/health?pretty'' : Cluster health check [[https://www.elastic.co/guide/en/elasticsearch/reference/current/cluster-health.html|Cluster Health]]
===== Docker로 띄우면서 Clustering 할 때 =====
* [[:docker|Docker]]로 ES를 띄울 경우 ''network'' 설정이 복잡해진다.
* [[https://www.elastic.co/guide/en/elasticsearch/reference/current/docker.html|Install Elasticsearch with Docker | Elasticsearch Reference]]
* 가장 쉬운 해결책 : ''network.host=0.0.0.0''으로 하고 docker 실행시 ''%%--%%net=host'' 옵션을 준다. 하지만 이 경우 보안상 등의 문제가 있을 수 있다고 함.
* [[http://stevesmashcode.com/devops/Elastic-Search-in-Docker/|How to Setup Elastic Search in Docker Containers]]
* 더 좋은 방법은 docker 를 띄우는 HOST의 IP를 ''network.publish_host''에 직접 바인딩해준다.
# network.host는 삭제하고, bind_host는 아래와 같이. eth0 는 다른 interface 일 수 있음
network.bind_host: _eth0:ipv4_ # 혹은 0.0.0.0 도 가능한지 확인할 것.
# elasticsearch 실행시 network.publish_host를 인자로 넘기고,
--network.publish_host $ES_PUBLISH_HOST
# docker 실행시에 다음 명령으로 해당 Host 서버의 IP값을 넣어준다.
docker run ... -e ES_PUBLISH_HOST=`hostname -I | awk '{print $1}'`
# AWS EC2 인스턴스에서는
docker run ... -e ES_PUBLISH_HOST=`curl -s http://169.254.169.254/latest/meta-data/local-ipv4`
===== Docker로 띄울 때 옵션 =====
Docker run 시에 다음 옵션을 추가해야 한다.
# JVM Heap Swap 방지 설정이 돼 있을 때 아래 옵션을 줘서 실행해야 한다. (bootstrap.mlockall: true)
# --cap-add=IPC_LOCK --ulimit memlock=-1:-1
docker run --cap-add=IPC_LOCK --ulimit memlock=-1:-1 ...
# 그렇지 않으면 다음과 같은 오류 발생하고 메모리 설정이 올바로 작동 안함
Unable to lock JVM Memory: error=12,reason=Cannot allocate memory
This can result in part of the JVM being swapped out.
Increase RLIMIT_MEMLOCK, soft limit: 65536, hard limit: 65536
These can be adjusted by modifying /etc/security/limits.conf, for example:
# allow user 'someuser' mlockall
coupang soft memlock unlimited
coupang hard memlock unlimited
If you are logged in interactively, you will have to re-login for the new limits to take effect.
JVM Heap Dump를 떠야 할 때 대비해서 다음 옵션도 추가
--cap-add=SYS_PTRACE
===== Linux 설정 =====
* [[https://www.elastic.co/guide/en/elasticsearch/reference/current/vm-max-map-count.html|Virtual memory | Elasticsearch Reference]]
sysctl -w vm.max_map_count=262144
* [[linux:performance|Linux Performance]]
===== 환경변수 =====
* ''JAVA_OPTS'' : Java 기본 옵션들
* ''ES_HEAP_SIZE'' : ''-Xmx, -Xms''에 같은 값으로 들어감
* ''ES_HEAP_NEWSIZE'' : ''-Xmn''
* ''ES_DIRECT_SIZE'' : ''-XX:MaxDirectMemorySize''
* ''ES_GC_OPTS'' : [[java:gc|Java Garbage Collection]] 관련옵션
* ''ES_GC_LOG_FILE'' : GC log 파일관련 옵션
===== 최적화 =====
* [[https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-replication.html|Reading and Writing documents]]
* ''index.refresh_interval: 시간s'' : 인덱스를 push 하는 시간이라고 보면 되는데 ''5s'' 형태로 준다. 길수록 CPU 점유율은 떨어지지만 검색에 안나오는 시간도 길어진다.
* ''bootstrap.mlockall: true'' : Linux 등에서 ES의 메모리를 swapping 하지 않게 설정 등.
* [[https://qbox.io/blog/optimizing-elasticsearch-how-many-shards-per-index|Optimizing Elasticsearch How Many Shards per Index? 최적의 Shard 갯수는]]
* 불필요하게 많은 Shard는 메모리와 리소스를 현저히 낭비하게 만든다.
* 메모리는 31GB 혹은 32bit Pointer가 될수 있는 max 값.
* Shard 는 최대 30GB가 될 정도 수준으로 구성.(Replica 도 계산시 단일 Shard로 쳐서)
* [[https://www.elastic.co/guide/en/elasticsearch/reference/current/tune-for-search-speed.html|Tune for search speed]]
* [[https://qbox.io/blog/optimizing-elasticsearch-how-many-shards-per-index|Optimizing Elasticsearch: How Many Shards per Index?]]
===== Write Performance =====
* Sharding 을 하지 않을 경우 모든 Write 요청이 하나의 Primary Data Node로 집중된다.
* Sharding 을 하면 각 Shard 별 Data Node로 분할 된다.
* Write Thread 는 CPU 갯수만큼 생성된다. 그리고 Queue가 200개 할당된다.
* Qeueue 갯수를 넘는 Write/Update 요청이 들어오면 reject 오류가 발생한다.
* Write Thread 를 늘리고자 한다면 Scale Up 해서 CPU 갯수를 늘린다. Queue 갯수를 늘리는 것은 미봉책이므로 하지 않는 것이 좋다.
* [[https://www.elastic.co/guide/en/elasticsearch/reference/current/tune-for-indexing-speed.html|Tune for indexing speed]]
* [[https://www.elastic.co/kr/blog/why-am-i-seeing-bulk-rejections-in-my-elasticsearch-cluster|Why am I seeing bulk rejections in my Elasticsearch cluster?]]
* [[https://www.elastic.co/guide/en/elasticsearch/reference/current/modules-threadpool.html|Thread Pool]]
* [[https://www.datadoghq.com/blog/elasticsearch-performance-scaling-problems/|How to solve 5 Elasticsearch performance and scaling problems]]
* [[https://brunch.co.kr/@alden/36|rejected exception의 의미와 조치 방법]]
* ''cat threadpool''
GET /_cat/thread_pool
===== Memory =====
* **32GB** 넘기지 말 것.
* [[https://brunch.co.kr/@alden/35|ElasticSearch와 Heap 메모리]]
===== G1 GC =====
* G1 GC로 가려면 [[search:lucene|Lucene]] 관련 버그들이 해결된 [[java:10|Java 10]] 이상 버전 권장.
* [[https://brunch.co.kr/@alden/45|G1 GC 적용과 JVM Upgrade]]
* [[https://medium.com/naukri-engineering/garbage-collection-in-elasticsearch-and-the-g1gc-16b79a447181|Garbage Collection in Elasticsearch and the G1GC – Naukri Engineering – Medium]]
* [[https://sematext.com/blog/java-9-elasticsearch-benchmark/|Java 9 Elasticsearch Benchmark: upgrading benefits]]
===== Disk Size =====
* [[https://www.elastic.co/guide/en/elasticsearch/reference/current/tune-for-disk-usage.html|Tune for disk usage ]]
===== RollingFileAppender로 변경 =====
* 로그의 수집 몇 관리가 어려운 경우 차라리 [[https://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/RollingFileAppender.html|RollingFileAppender]]를 사용하는게 관리 측면에서 유리함
* 용량이 증가해서 maxFileSize(byte) 를 초과하면 maxBackupIndex 한도 내에서 파일 이름에 번호를 붙이면서 덮어쓴다.
file:
type: rollingFile
file: ${path.logs}/${cluster.name}.log
maxFileSize: 104857600
maxBackupIndex: 10
layout:
type: pattern
conversionPattern: "[%d{ISO8601}][%-5p][%-25c] %.10000m%n"
===== 주의점 =====
* 한 클러스터에서는 모두 동일 JVM 버전을 사용해야한다. 안 그러면 직렬화가 달라서 문제가 발생할 수 있다.
* 한 번 Version Upgrade 한 뒤 indexing을 하면 다시 Downgrade 할 수 없다. index를 백업 한 뒤에 업그레이드하라.
* 2.x 버전에서 Tokenizer Plugin 을 사용할 때, 기본 Tokenizer type 이름과 tokenizer 이름이 다를경우 해당 토크나이저의 설정 정보가 처음에는 올바른 상태로 그리고 다시 한 번은 null 인 상태로 ''XxxTokenizerFactory'' 생성자가 한 번 더 호출되는 문제가 있다. 이에 따라 type 이름과 토크나이저 이름을 동일하게 맞춰줘야 했다. 이 경우 생성자가 인덱스당 한 번씩만 호출되었다.
===== 참조 =====
* [[http://blog.trifork.com/2013/10/24/how-to-avoid-the-split-brain-problem-in-elasticsearch/|How to avoid the split-brain problem in elasticsearch]]
* [[http://www.popit.kr/%ec%97%98%eb%9d%bc%ec%8a%a4%ed%8b%b1%ec%84%9c%ec%b9%98es-%ed%81%b4%eb%9f%ac%ec%8a%a4%ed%84%b0-%ec%9e%ac%ec%8b%9c%ec%9e%91-%ed%98%b9%ec%9d%80-%ec%97%85%ea%b7%b8%eb%a0%88%ec%9d%b4%eb%93%9c-tip/|엘라스틱서치(ES) 클러스터 재시작 혹은 업그레이드 Tip | Popit]]
* [[https://blog.frankel.ch/elasticsearch-api-cheatsheet/|ElasticSearch API cheatsheet]]
* [[https://www.javacodegeeks.com/2017/03/elasticsearch-java-developers-elasticsearch-java.html|Elasticsearch for Java Developers: Elasticsearch from Java | Java Code Geeks - 2017]]
* [[https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-mapping-charfilter.html|Mapping Char Filter | Elasticsearch Reference [6.2] | Elastic]] 특수 문자등의 검색
* [[https://esbook.kimjmin.net/|Elastic 가이드 북 - Elastic 가이드북]]
* [[https://aws.amazon.com/ko/premiumsupport/knowledge-center/opensearch-latency-spikes/|Amazon OpenSearch Service의 검색 대기 시간 스파이크 문제 해결]]