hit

Elasticsearch 2015. 5. 31. 23:39




웹에서 hit는 웹 싸이트 분석에서 사용되는 통계이다. hits와 visits는 때때로 상호 교환 할 수 있는 용어로 사용되지만, 서로 다르다. 사용자가 웹 페이지를 방문하면 방문이 기록된다. hit는 웹 서버로부터 다운로드된 각각의 로컬 파일 자원 참조 개수를 의미한다.  따라서, 1 page 내에 파일 리소스가 10개이면 (html, css, javascript 등등), 1 vistit에 10개의 hit라 표현할 수 있다.


검색에서 hit는 주어진 검색 질의에 대한 검색 결과의 개수를 의미한다. 1,000,000 개의 구글 검색을 생성하면 질의에 의한 1,000,000 개의 hit 라 표현할 수 있다.


elasticsearch의 hit도 검색의 포함된 용어이기 때문에 '검색 결과' 또는 '검색 결과 개수'로 해석하면 좋은 것 같다. 

Posted by '김용환'
,


일래스틱서치의 문서를 보면 내부에서 낙관적 동시 제어를 지원한다고 얘기를 한다.

실제 versioning도 지원되는 것도 그 배경이다.


동시성 충돌 때문에 레코드를 잠그는 비관적 동시 제어(select for update) 하는 DB와 다르다. 


한 트랙잭션이 다른 트랙잭션과 충돌할 가능성이 적은 곳에서 사용된다. 


그렇지만, 충돌이 되더라도 반영을 안하는 것은 아니다. 원 데이터가 수정이 되었나 체크해서 수정된 것이 판별되면 이미 실행된 트랙잭션이 롤백이 일어나고 다시 시작한다. 따라서 일래스틱서치에서는 수정된 데이터를 읽을 수 있도록 처리 되어 있다.


일래스틱서치에서 트랙잭션이 동시에 일어나 데이터가 변경되면 version이 증가된다. GET 요청에 대해서 확인할 수 있다.

원래 요청했던 version이 1인데, 응답의 body에는 2가 리턴된다.  (다큐먼트를 색인할 때 version의 디폴트 값은 1이다) 


 



PUT /website/blog/1?version=1 

.. "_version" : 2 ..



그러나 처리 중간에 트랜잭션에 의해서 값이 변경될 수 있다. 그 때는 409 conflict 응답을 받는다.

(REST API는 확실히 지원하나, 언어별 클라이언트에서는 의도하지 않는 응답이 올 수 있다고 한다.)


일래스틱서치는 변경 또는 삭제 요청에만 version 파라미터를 사용할 수 있는 낙관적 동시 제어를 지원한다.


스크립트 실행 동안 변경이 일어나면, 스크립트가 변경된 데이터로 재실행된 결과를 얻는다.



출처 : 


https://www.elastic.co/guide/en/elasticsearch/guide/master/version-control.html


https://www.elastic.co/guide/en/elasticsearch/guide/current/optimistic-concurrency-control.html


https://www.elastic.co/blog/elasticsearch-versioning-support


http://en.wikipedia.org/wiki/Optimistic_concurrency_control


'Elasticsearch' 카테고리의 다른 글

[elasticsearch] Query vs Filter  (0) 2015.06.01
hit  (0) 2015.05.31
[elasticsearch] 색인 앨리어스 (별명)  (0) 2015.05.28
[elasticsearch] failed to put mappings on indices  (0) 2015.05.27
[elasticsearch] flush, refresh, optimization  (0) 2015.05.26
Posted by '김용환'
,



색인 앨리어스는 색인에 대한 앨리어스(별명) 치고는 유용한 기능이 있다.



단순히 앨리어스를 주는 것 뿐 아니라.
필터(filter)와 라우팅(routing) 매개변수를 정의하기 위해 사용될 수 있다.


$ curl -XPOST 'http://localhost:9200/myindex/_aliases/alias1' -d '
{
  "filter" : {
  "term" : { "user" : "user_1" }
  },
  "search_routing" : “1,2,3",
  "index_routing" : "2"
}'



필터는 질의에 데이터를 걸리내기 위해 자동으로 추가될 수 있으며,
앨리어스를 통한 라우팅은 검색 작업(search)과 색인 작업(index)동안 어느 샤드로 요청할지를 미리 설정할 수 있다.

위의 예제에서 보듯이 search_routing은 여러 개의 값을 가진 라우팅 키를, index_routing은 단 하나의 라우팅 값을 가질 수 있다. 즉, 내가 어느 샤드에 어떤 정보가 저장되어 있는지 안다면 굉장히 효율적으로 성능을 향상시킬 수 있다.

(일래스틱서치는 특정 샤드를 라우팅 하는 매개변수를 전달하지 않으면 내부적으로 모든 샤드로 확산하여 요청하고, 그 결과를 수집하기 때문에 성능상 취약한 부분이 존재하기 때문에.. 샤드 값을 잘 알수만 있다면 성능 향상의 요인이 될 수 있다.)



출처 : 

https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-aliases.html

Posted by '김용환'
,



elasticsearch에서 failed to put mappings on indices (NPE) 가 발생하면 용도에 맞는 json 요청이라는 뜻이다.

elasticsearch가 친절하게 에러 메시지를 전달해주는 것이 없어서(결과적으로 실패했다는 로그) 조금 혼란을 줄 수 있긴 한데..

몸으로 때우는 수밖에 없는 것 같다. 


[DEBUG][action.admin.indices.mapping.put] [Prototype] failed to put mappings on indices [[my_index]], type [my_type]

java.lang.NullPointerException

    at org.elasticsearch.common.xcontent.XContentFactory.xContent(XContentFactory.java:137)

    at org.elasticsearch.common.xcontent.XContentHelper.convertToMap(XContentHelper.java:113)



클라이언트에서는 아래와 같은 에러가 발행한다.

{"error":"RemoteTransportException[[olive047][inet[/172.17.48.122:9300]][indices:admin/mapping/put]]; nested: NullPointerException; ","status":500}



해결을 위해서는 setting와 mapping 관련 url이 맞는지 확인한다.

* /_setting url 에 mapping json을 요청했는지, 

* /_mapping url에 setting json을 요청했는지.

* /_mapping url에 setting, mapping json을 요청했는지.

* /{index_name} 에 setting, mapping 을 잘 입력해서 정상적으로 요청했는지 (<-- 이거 정상)




test.json에 setting와 mapping 을 포함한 json 파일일 때, 아래와 같은 url 요청시에 failed to put mappings on indices (NPE)  에러 발생한다.

$ curl -s -XPUT http://localhost:9200/suggest_test/type/_mapping -d test.json





test.json에 setting와 mapping 을 포함한 json 파일일 때, 아래와 같은 url 요청시에 문제가 없다.

$ curl -s -XPUT http://localhost:9200/suggest_test -d test.json


Posted by '김용환'
,





1. flush 



elasticsearch의 flush는 메모리와 트랜잭션 로그를 디스크로 저장한다.


elasticsearch는 lucene을 의존한다. lucene의 색인(index) 작업은 fsync를 사용하는데, fsync가 비싼 비용이 있어서 lucene은 여러 세그먼트로 색인을 관리하고 있다. 

in memory buffer를 이용하여 sync 작업이 발생하면 fsync를 통해서 디스크에 저장한다.


curl -XPOST 'http://localhost:9200/myindex/_flush



2. refresh

refresh는 색인을 새로 고침의 의미가 있다. 즉, 검색이 되게 하는 (searchable)의 의미가 있다. 

refresh주기가 시간내 검색이 되느냐 안되는냐를 결정한다. (보통 1초를 사용)

참조로 elasticsearch 문서에서는 거의 실시간(near real time, NRT)라는 단어를 사용하고 있다. 

https://www.elastic.co/guide/en/elasticsearch/guide/current/near-real-time.html



만약 refresh 주기를 지정하지 않으면, 따로 호출을 주어 refresh를 임의로 호출하게 할 수 있다. 



curl -XPOST 'http://localhost:9200/myindex/order/_settings' -d '{ "refresh_interval": -1 }'




curl -XPOST 'http://localhost:9200/myindex/order/_refresh'



참고로 flush와 refresh는 동시에 사용될 수 있다. 


curl -XPOST 'http://localhost:9200/myindex/_flush?refresh=True'




3. 최적화(optimization)


파편화된 세그먼트를 세그먼트를 줄이고 검색 성능을 빨리 하도록 하여 색인을 통합한다. 검색 성능을 높이는데 의미를 두고 있다.

lucene이 사용하지 않는 세그먼트와 다큐먼트를 정리하는 IO 작업을 통해서 검색을 빠르게 한다. 세그먼트 수를 최소화시킨다. 최소한의 파일에만 접근하도록 한다. 



$ curl -XPOST 'http://localhost:9200/myindex/_optimize'




최적화의 매개변수는 3개이다. 

https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-optimize.html






Posted by '김용환'
,



elasticsearch에서 myindex 인덱스를 생성한다. 



$ curl -XPOST 'http://localhost:9200/myindex'


$ curl -XPUT 'http://localhost:9200/myindex/order/_mapping' -d '{
"order" : {
"properties" : {
"id" : {"type" : "string", "store" : "yes" , "index":"not_analyzed"},
"date" : {"type" : "date", "store" : "no" , "index":"not_analyzed"},
"customer_id" : {"type" : "string", "store" : "yes" , "index":"not_analyzed"},
"sent" : {"type" : "boolean", "index":"not_analyzed"},
"name" : {"type" : "string", "index":"analyzed"},
"quantity" : {"type" : "integer", "index":"not_analyzed"},
"vat" : {"type" : "double", "index":"no"}
}
}
}'




한 번 더 order 매핑 POST메소드를 요청하면, 이미 존재한다고 예외가 발생한다.


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



타입만 새로 바꾸어 mapping을 구성하고자 한다. vat는 원래 index가 no였는데, analyzed로 변경하려 하지만, vat 가 이미 다른 색인 값 매퍼로 되 었다고 400에러가 발생한다.

$ curl -XPUT 'http://localhost:9200/myindex/order/_mapping' -d '{
 "order" : {
 "properties" : {
 "id" : {"type" : "string", "store" : "yes" , "index":"not_analyzed"},
 "date" : {"type" : "date", "store" : "no" , "index":"not_analyzed"},
 "customer_id" : {"type" : "string", "store" : "yes" , "index":"not_analyzed"},
 "sent" : {"type" : "boolean", "index":"not_analyzed"},
 "name" : {"type" : "string", "index":"analyzed"},
 "quantity" : {"type" : "integer", "index":"not_analyzed"},
 "vat" : {"type" : "double", "index":"analyzed"}
 }
}
 }'
{"error":"MergeMappingException[Merge failed with failures {[mapper [vat] has different index values, mapper [vat] has different tokenize values]}]","status":400}

이럴 때에는 ignore_conflicts=true 옵을 주면,
의도대로 변경이 된다.


$ curl -XPUT 'http://localhost:9200/myindex/order/_mapping?ignore_conflicts=true' -d '{
 "order" : {
 "properties" : {
 "id" : {"type" : "string", "store" : "yes" , "index":"not_analyzed"},
 "date" : {"type" : "date", "store" : "no" , "index":"not_analyzed"},
 "customer_id" : {"type" : "string", "store" : "yes" , "index":"not_analyzed"},
 "sent" : {"type" : "boolean", "index":"not_analyzed"},
 "name" : {"type" : "string", "index":"analyzed"},
 "quantity" : {"type" : "integer", "index":"not_analyzed"},
 "vat" : {"type" : "double", "index":"analyzed"}
 }
 }
}'

{"acknowledged":true}



Posted by '김용환'
,


elasticsearch에서 모든 인덱스(색인)을 삭제하는 방법은 다음과 같다.



$ curl -XDELETE 'http://localhost:9200/*'


또는 


$ curl -XDELETE 'http://localhost:9200/_all'





상용 서비스에서는 괜히 호출했다가 문제가 될 수 있으니, 방어 설정을 elasticsearch.yml에 둘 수 있다.


action.destructive_requires_name: true



만약 전체 삭제를 시도하려 했더라면 다음과 같이 에러가 발생하게 되고 전체 삭제가 안 될 것이다.


$ curl -XDELETE 'http://localhost:9200/_all'

{"error":"ElasticsearchIllegalArgumentException[Wildcard expressions or all indices are not allowed]","status":400}



Posted by '김용환'
,


elasticsearch 1.4.3 으로 테스트해봤던 내용 공유



1. refresh_interval 값 성능


전에, refresh_interval 값이 성능에 영향이 있다고 해서 테스트해보았다. 


refresh_inteval 로 주어진 값은 인덱싱(색인)을 얼마나 하는 주기를 의미한다. 일종의 flush 같은 개념인데, 

길면 길수록 성능은 좋아지고, 짧을 수록 성능은 좋지 않다. 


확실히 짧게 주는 것보다는 길게 주는 것이 좋다. cpu 5~15% 차이가 발생 했다.


그러나, 문제는 서비스의 영향도가 있어서 짧게 줄 수 없다.. 


로그 수집하는 정도나. refresh_interval을 길게 줄 수 있을 듯 하다.


curl -XPUT localhost:9200/movies/_settings -d '{

    "index" : {

        "refresh_interval" : "30s"

    } }'



(좋은 참고 : http://blog.sematext.com/2013/07/08/elasticsearch-refresh-interval-vs-indexing-performance/ )





2. optimize 옵션 주기


optimize옵션을 주면 빠른 검색이 되도록 최적화 인덱싱을 한다. 호출 순간에서는 성능이 안좋아질 수 있으나, 장기적으로는 성능이 좋아진다.


cpu 1~3% 정도로 성능이 좋아졌다.


$ curl -XPOST 'http://localhost:9200/movie/_optimize'



(좋은 참고 : http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/indices-optimize.html#optimize-parameters)



3. 삭제시 좋은 성능이 나오도록 튜닝 요소


인덱스를 이루는 세그먼트가 삭제로 인해서 큰 세그먼트로 compatction이 일어나도록 잘 튜닝할 수 있다. 

서비스 성격에 맞게 변경해야 한다. 



index.merge.async: true
index.merge.policy.merge_factor: 10
index.merge.policy.expunge_deletes_allowed: 10
index.merge.policy.floor_segment: 1mb
index.merge.policy.max_merge_at_once: 8
index.merge.policy.max_merge_at_once_explicit: 2
index.merge.policy.max_merged_segment: 1gb
index.merge.policy.segments_per_tier: 10



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

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




4. Sorting 성능 개선


Sorting 성능을 개선할 수 있다. 서비스 성격에 맞게 변경해야 한다.


index.fielddata.cache: soft 

indices.fielddata.cache.size: 80%

indices.fielddata.cache.expire: 24h


https://www.elastic.co/guide/en/elasticsearch/reference/current/index-modules-fielddata.html



5. 검색 ThreadPool 설정


threadpool:

    index:

        type: fixed

        size: 30

        queue_size:-1 



https://www.elastic.co/guide/en/elasticsearch/reference/1.x/modules-threadpool.html




6. (Data Node) JVM GC 알고리즘 


다양한 방식으로 여러 GC 방법 (CMS, G1)으로 테스트 해봤으나, elasticsearch에서 제공하는 디폴트의 jvm 옵션(cms)이 최강이었음. 


JVM8 최신으로 G1 알고리즘으로 Full GC 시간을 좀 줄일 수 있지만, 자주 조금 줄일 수 있었지만, CPU가 상당히 높게 나왔다. CMS는 다양한 옵션으로 했지만, 디폴트 옵션만큼의 CPU와 Full GC 시간을 이길 수 없었따. 


(참고 : http://blog.sematext.com/2013/06/24/g1-cms-java-garbage-collector/)




7. (Data Node) JVM 메모리

JVM 메모리가 많을 수록 유리할 수 있지만, Full GC 시간이 점점 길어졌다. 한 JVM의 메모리는 작은 것이 가장 성능이 좋았다.


인터넷의 여러 회사 블로그에서 대용량 트래픽을 elasticsearch 대용량 메모리로 처리했다는 내용(linked, stackoverflow)을 참조해고 해봤는데, 서비스의 성격(CRUD)에 따라 다른 것 같다. 


Posted by '김용환'
,
 elasticsearch의 대가 , Rafal Kuc 아저씨의 Scaling Massive Elasticsearch clusters !!!

Scaling massive elastic search clusters - Rafał Kuć - Sematext from Rafał Kuć


Posted by '김용환'
,

elasticsearch에서 매핑 따로 색인 따로 호출해도 되지만, 하나로 묶어도 된다. (사실 이 묶음 요청이 가장 elasticsearch 만의 큰 장점인듯 하다.)



curl -XPOST localhost:9200/stock -d '{

  "settings" : { // 색인 초기화

    "number_of_shards" : 10,

    "number_of_replicas" : 2

  },

  "mappings" : { // 매핑 & 색인

    "order" : {

      "properties" : {

        "id" : {"type" : "string", "store" : "yes" , "index":"not_analyzed"},

        "date" : {"type" : "date", "store" : "no" , "index":"not_analyzed"}

      }

  }

}  




Posted by '김용환'
,