Elasticsearch에서 mlock이 정상적으로 되는 방법


mlock을 하지 않은 설정에서 서버 시작을 하면, log에서 다음과 같은 warn이 발생한다. 


[2015-02-25 15:36:46,784][WARN ][common.jna               ] Unable to lock JVM memory (ENOMEM). This can result in part of the JVM being swapped out. Increase RLIMIT_MEMLOCK (ulimit).




이를 위해서 다음과 같은 작업을 진행한다. 


1. swap을 끈다. 


$ sudo swapoff -a


2. swappiness를 끈다. (최신 커널에서는 vm.swappiness의 값이 0 인 상태에서 스왑을 쓰면 os에서 kill할 수 있어서 1로 설정한다. 구 커널에서는 vm.swappiness를 0으로 해도 상관없다.)


$ sudo sysctl vm.swappiness=1

$ cat /proc/sys/vm/swappiness

1



1,2 위의 작업이 재시작 이후에도 동작되도록 설정

vi /etc/rc.d/rc.local




3. /etc/security/limits.conf 파일 추가

*       soft    memlock unlimited

*       hard    hemlock unlimited


4. conf/elaticsearch.yml 파일에서 bootstrap.mlockall: true으로 변경한다. 



5. logout후 login이 하고 elasticsearch 실행

$ curl http://localhost:9200/_nodes/process?pretty


전체 클러스터에서 mlock이 정상적으로 되었는지 체크할 수 있다. 








Posted by '김용환'
,

Elasticsearch의 메모리 설정을 빨리 하기 위해서 index.store.type을 memory로 변경하면, Lucene의 RAMIndexStore정말 성능이 좋아진다. 그 이유는 모든 것을 파일이 아닌 메모리에 쓰기 때문이다. 다만, 파일로 저장하지 않기 때문에 전체 shutdown 후 재시작 때, 또는 memory가 꽉 차면 최악의 상황이 발생한다.  


http://www.elasticsearch.com/guide/en/elasticsearch/reference/current/index-modules-store.html



Lucene 소스를 보면 파일 저장을 하지 않을 뿐더러 File 자체를 쓰지 않고 ArrayList를 사용하는 방식이다. 따라서 다른 Nio 소스와 비교해 볼때, 파일 저장이 되지않음을 소스로서 확인할 수 있다. 

http://search-lucene.com/c/ElasticSearch:rc/main/java/org/elasticsearch/index/store/ram/RamIndexStore.java%7C%7Crealize+%252B%2528index+space%2529



용도는 실제 성능을 memory와 비교하는 테스트 또는 플러그인 테스트할 때 유용한 것 같다. 



http://quia.cf/orange/pooxy4/nph-poxy.pl/es/20/http/stackoverflow.com/questions/25057334/elasticsearch-in-memory-speed

http://www.chazine.com/archives/3565

Posted by '김용환'
,



출처 

http://www.elasticsearch.org/guide/en/elasticsearch/guide/current/_queries_and_filters.html



Elasticsearch의 query와 filter의 비교


filter

- full text search가 아닌 것, yes/no 조건에 주로 사용

  regex filter 사용하면, 엄청 느리다..

- scoring이 계산되지 않는다.

- filter 결과가 캐싱됨

- 응답 속도가 빠름 (캐싱 때문에.)

- 검색될 결과를 줄이는 데 목표가 있음


query

- full text search(전문검색)에 주로 사용

   wildcard, 그냥 query에도 빠르다.

- scoring 계산 (relevance)

- query 결과가 캐싱되지 않음

- 응답 속도가 느림



Posted by '김용환'
,


출처 

http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/mapping-core-types.html

http://www.elasticsearch.org/guide/en/elasticsearch/guide/current/analysis-intro.html

http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/mapping-analyzer-field.html


Elasticsearch의 index 속성은 가장 내가 잘 이해 못했던 내용 중의 하나이다. index 용어를 많이 쓰이기도 하지만, 번역(책)에서 불러 일으키는 오해도 약간 있는 듯 하다. 


 "user" : {
               
"type" : "string",
               
"index" : "not_analyzed",
               
"norms" : {
                   
"enabled" : false
               
}
           
}

index는 analyzer 적용을 할지 안할지를 결정한다. 3가지 값 중 하나가 들어간다.

1. analyzed -  analyzer가 있다는 뜻이다. (또는 custom 정의 analyzer가 있다.)  analyzed는 "broken down into searchable terms"로 만든다는 것이다. 토큰으로 잘라 검색한다. "back to the future" 라는 단어는 'back', 'to',  'the', 'future'라는 토큰으로 나누어진다는 것을 의미



2. not_analyzed - analyzer가 없다. (또는 built in analyzer를 쓰지 않는다는 얘기이다.)

배열로 멀티 검색할 때는 not_analyzed를 써야 한다. 

http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/mapping-array-type.html


3. no - indexing하지 않는다. 순수하게 저장용으로 쓸 때 유용하다. 




Posted by '김용환'
,



출처

http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/cluster-nodes-shutdown.html


elasitcsearch 서버를 재시작하는 방법


es가 장애 발생시에는 자동으로 reallocation이 발생한다. 단순한 설정 변경 이후에 재시작이라면 단순히 이 방식을 사용하면 좋다. 



1. relocation

 curl -XPUT localhost:9200/_cluster/settings -d '{

                "transient" : {

                    "cluster.routing.allocation.enable" : "none"

                }

        }'


2. shutdown

curl -XPOST 'http://localhost:9200/_cluster/nodes/_local/_shutdown'



3. background로 실행

./bin/elasticsearch -d



4. reallocation 이 되도록 변경 (원래대로)


curl -XPUT localhost:9200/_cluster/settings -d '{

                "transient" : {

                    "cluster.routing.allocation.enable" : "all"

                }

        }'




구장비를 반납하고 새 장비를 추가할 때는 다음과 같다. 



1. allocation을 하지 않도록 함


 curl -XPUT localhost:9200/_cluster/settings -d '{
                "transient" : {
                    "cluster.routing.allocation.enable" : "none"
          }
  }' 



2. 새 장비에서 데몬 실행



bin/elasticsearch -d



3. 반납장비는 데몬 종료


curl -XPOST 'http://localhost:9200/_cluster/nodes/_local/_shutdown'





4. reallocation 실시 


curl -XPUT localhost:9200/_cluster/settings -d '{

                "transient" : {

                    "cluster.routing.allocation.enable" : "all"

       }

}'




참고로 1대를 빼고, 1대를 추가한다 하더라도 동일한 shard가 반드시 reallocation되지 않는다. 

실제 재시작 전의 데이터의 index를 살펴보면 아래와 같았다. 

$ ls elasticsearch/nodes/0/indices/movies/
0/  1/  10/ 12/ 2/  5/  6/  9/

재시작 후에 살펴보니 샤드가 일부 변경된 것을 확인하면서 reallocation이 예상대로 되지 않음을 확인했다. 

$ ls elasticsearch/nodes/0/indices/movies/
0/  1/  10/ 12/ 3/  5/  6/  9/


Posted by '김용환'
,


elasticsearch에 json 생성파일로 인덱스를 생성하는 예제이다.  (그리고 필드 변경/삭제에 관련한 이슈가 있는 예제이다.)


만약 동일한 이름의 인덱스가 만들어져 있으면, es는 400 에러를 발생한다. 따라서, 인덱스를 삭제하고 다시 해야 한다.


$ curl -s -XPOST http://localhost:9200/feeds/ -d @settings.json

{"error":"IndexAlreadyExistsException[[feeds] already exists]","status":400}


삭제한다. 

 $ curl -s -XDELETE http://localhost:9200/feeds/

{"acknowledged":true}


settings.json 파일을 생성한다.



$ cat settings.json

{

    "mappings": {

        "feed_item": {

            "_source": {

                "enabled": true

            },

            "properties": {

                "profile_id": {

                    "type": "integer"

                },

                "aid": {

                    "type": "long"

                },

                "type": {

                    "type" : "string",

                    "analyzer" : "string_lowercase"

                }

            }

        }

    },

    "settings": {

        "analysis": {

            "analyzer": {

                "string_lowercase": {

                    "filter": "lowercase",

                    "tokenizer": "keyword"

                }

            }

        },

        "index": {

            "number_of_replicas": "1",

            "number_of_shards": 10,

            "refresh_interval": "2s",

            "store.type" : "memory"

        },

        "routing": {

            "required": true

        }

    }

}



인덱스를 생성한다. 

$ curl -s -XPOST http://localhost:9200/feeds/ -d @settings.json

{"acknowledged":true}


정상적으로 인덱스가 생성되었는지 확인한다. _mapping으로 확인할 수 있다. 

$ curl -s -XGET http://localhost:9200/feeds/_mapping?pretty

{

  "feeds" : {

    "mappings" : {

      "feed_item" : {

        "properties" : {

          "aid" : {

            "type" : "long"

          },

          "profile_id" : {

            "type" : "integer"

          },

          "type" : {

            "type" : "string",

            "analyzer" : "string_lowercase"

          }

        }

      }

    }

  }

}


필드를 동적으로 추가할 수 있다. 


curl -s -XPUT http://localhost:9200/feeds/_mapping/feed_item -d '

 {

   "feed_item" : {

     "properties" : {

     "read" : { "type" : "boolean" }

     }

   }

 }'




정상적으로 property가 추가되었는지 확인한다. 


{

  "feeds" : {

    "mappings" : {

      "feed_item" : {

        "properties" : {

          "aid" : {

            "type" : "long"

          },

          "profile_id" : {

            "type" : "integer"

          },

          "read" : {

            "type" : "boolean"

          },

          "type" : {

            "type" : "string",

            "analyzer" : "string_lowercase"

          }

        }

      }

    }

  }

}



특정 properties를 삭제해 보자. DELETE 내리는 순간 모두 삭제된다.!!! 



$ curl -s -XDELETE http://localhost:9200/feeds/_mapping/feed_item -d '

 {

   "feed_item" : {

     "properties" : {

    "read" : { "type" : "boolean" }

    }

   }

}'


$ curl -s -XGET http://localhost:9200/feeds/_mapping?pretty

{ }



* 주의할 점

- mapping 명령어 사용시에는 DELETE를 신중히 해야 한다. 

- 한번 mapping되면 property를 추가할 수 있지만, 변경이나 삭제가 불가능하다.  


(property라 부르는 것들은 사실상 es에서는 field라 불리운다.)


Posted by '김용환'
,


공부하는데 도움되는 자료


http://www.slideshare.net/g9yuayon/elasticsearch-in-netflix?related=4


http://highscalability.com/blog/2014/7/21/stackoverflow-update-560m-pageviews-a-month-25-servers-and-i.html


http://www.slideshare.net/gnurag/workshop-learning-elasticsearch


http://www.slideshare.net/MarkGreene4/building-a-crm-on-top-of-elasticsearch


http://www.slideshare.net/deview/2d1elasticsearch


http://blog.qbox.io/elasticsearch-aggregations


http://jjeong.tistory.com/712


http://www.slideshare.net/xpressengine/xecon-phpfest2014elasticsearch






플러그인 헤드

http://mobz.github.io/elasticsearch-head/


definitive guide 

http://www.elasticsearch.org/guide/en/elasticsearch/guide/current/index.html


기본 개념 (완전 중요)

http://www.elasticsearch.org/guide/en/elasticsearch/guide/current/replica-shards.html#replica-shards

http://www.elasticsearch.org/guide/en/elasticsearch/guide/current/distributed-docs.html


read&write (완전 중요)

insert,delete,update는 원본 데이터 샤드, get은 replica shard로 보낸다. 

http://www.elasticsearch.org/guide/en/elasticsearch/guide/current/distrib-read.html

http://www.elasticsearch.org/guide/en/elasticsearch/guide/current/distrib-write.html



요청 관점에서 본 ES 중요 내용

http://www.elasticsearch.org/guide/en/elasticsearch/guide/current/distrib-write.html


java api

http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/index.html


튜닝 관련

http://evertrue.github.io/blog/2014/11/16/3-performance-tuning-tips-for-elasticsearch/

https://blog.codecentric.de/en/2014/05/elasticsearch-indexing-performance-cheatsheet/


https://groups.google.com/forum/#!topic/elasticsearch/-j7bpgNMHMQ


http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/setup-configuration.html


Posted by '김용환'
,



and, or 보다는 bool을 사용하는 것이 성능이 좋다고 한다. (2배 이상 좋아짐)


출처 : 

http://gibrown.com/2014/08/12/scaling-elasticsearch-part-3-queries/

Posted by '김용환'
,


scroll의 size 는 샤드 당 개수를 의미한다. 

그리고 디폴트 size는 10이다. 만약 샤드의 크기가 15이면 전체 size는 150개이다.  



http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-request-scroll.html

http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-request-from-size.html




하둡은 디폴트 size는 50이다. (샤드당 50개)


http://www.elasticsearch.org/guide/en/elasticsearch/hadoop/current/configuration.html

Posted by '김용환'
,



Elasticsearch 1.4.3(1.4.x 대도 다 그런 것 같다..) 부터는 아래 설정을 사용할 수 없다. (데이터가 이미 1.4.3 이하라면 내부적으로 변경이 되지만, 처음부터 아래 설정을 사용할 때는 에러가 발생한다.)


index.fielddata.cache: soft

  


자세한 내용은 아래를 참조한다. 

https://github.com/elastic/elasticsearch/blob/1.4/src/main/java/org/elasticsearch/index/fielddata/IndexFieldDataService.java




만약 사용하게 되면, 다음과 같은 에러가 발생한다. 

ElasticsearchIllegalArgumentException[cache type not supported [soft] for field [type]]; 



=> 아래와 같이 수정해야 한다. 


index.fielddata.cache: node




--- Stack Trace 

Parse Failure [Failed to parse source [{"query":{"filtered":{"query":{"match_all":{}}}},"aggregations":{"aggs":{"terms":{"field":"type","size":500}}}}]]]; nested: ElasticsearchIllegalArgumentException[cache type not supported [soft] for field [type]]; }
     at org.elasticsearch.action.search.type.TransportSearchTypeAction$BaseAsyncAction.onFirstPhaseResult(TransportSearchTypeAction.java:233)
     at org.elasticsearch.action.search.type.TransportSearchTypeAction$BaseAsyncAction$1.onFailure(TransportSearchTypeAction.java:179)
     at org.elasticsearch.search.action.SearchServiceTransportAction$6.handleException(SearchServiceTransportAction.java:249)
     at org.elasticsearch.transport.netty.MessageChannelHandler.handleException(MessageChannelHandler.java:185)
     at org.elasticsearch.transport.netty.MessageChannelHandler.handlerResponseError(MessageChannelHandler.java:175)
     at org.elasticsearch.transport.netty.MessageChannelHandler.messageReceived(MessageChannelHandler.java:125)
     at org.elasticsearch.common.netty.channel.SimpleChannelUpstreamHandler.handleUpstream(SimpleChannelUpstreamHandler.java:70)
     at org.elasticsearch.common.netty.channel.DefaultChannelPipeline.sendUpstream(DefaultChannelPipeline.java:564)
     at org.elasticsearch.common.netty.channel.DefaultChannelPipeline$DefaultChannelHandlerContext.sendUpstream(DefaultChannelPipeline.java:791)
     at org.elasticsearch.common.netty.channel.Channels.fireMessageReceived(Channels.java:296)
     at org.elasticsearch.common.netty.handler.codec.frame.FrameDecoder.unfoldAndFireMessageReceived(FrameDecoder.java:462)
     at org.elasticsearch.common.netty.handler.codec.frame.FrameDecoder.callDecode(FrameDecoder.java:443)
     at org.elasticsearch.common.netty.handler.codec.frame.FrameDecoder.messageReceived(FrameDecoder.java:310)
     at org.elasticsearch.common.netty.channel.SimpleChannelUpstreamHandler.handleUpstream(SimpleChannelUpstreamHandler.java:70)
     at org.elasticsearch.common.netty.channel.DefaultChannelPipeline.sendUpstream(DefaultChannelPipeline.java:564)
     at org.elasticsearch.common.netty.channel.DefaultChannelPipeline.sendUpstream(DefaultChannelPipeline.java:559)
     at org.elasticsearch.common.netty.channel.Channels.fireMessageReceived(Channels.java:268)
     at org.elasticsearch.common.netty.channel.Channels.fireMessageReceived(Channels.java:255)
     at org.elasticsearch.common.netty.channel.socket.nio.NioWorker.read(NioWorker.java:88)
     at org.elasticsearch.common.netty.channel.socket.nio.AbstractNioWorker.process(AbstractNioWorker.java:108)
     at org.elasticsearch.common.netty.channel.socket.nio.AbstractNioSelector.run(AbstractNioSelector.java:318)
     at org.elasticsearch.common.netty.channel.socket.nio.AbstractNioWorker.run(AbstractNioWorker.java:89)
     at org.elasticsearch.common.netty.channel.socket.nio.NioWorker.run(NioWorker.java:178)
     at org.elasticsearch.common.netty.util.ThreadRenamingRunnable.run(ThreadRenamingRunnable.java:108)
     at org.elasticsearch.common.netty.util.internal.DeadLockProofWorker$1.run(DeadLockProofWorker.java:42)
     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
     at java.lang.Thread.run(Thread.java:745)

Posted by '김용환'
,