데이터베이스/Elasticsearch

[번역] Elasticsearch 퍼포먼스 튜닝 방법 - ebay

반응형

Elasticsearch에 대해 검색하다가 ebay에 퍼포먼스 튜닝방법에 대해 좋은 글이 있어서 간단하게 정리해봤다. 새롭게 알게된 사실이 많아서 좋았다. 

정리 잘된 기술 블로그를 보는것은 책을 읽는거보다 훨씬 유익한 경우가 많은 것 같다.

 

Elasticsearch


엘라스틱 서치는 아파치 루씬을 기반으로한 검색과 분석 엔진으로 데이터를 실시간에 가깝게 보여주고 분석해 준다. 실시간성으로 분석과 검색을 위해서 많이 사용되는 엘라스틱 서치의 퍼포먼스는 무엇보다 중요한데 이를 위한 퍼포먼스 튜닝방법을 정리해보자.

높은 엘라스틱서치의 퍼포먼스를 위해서는 많은 처리량, 낮은 검색 지연시간등이 요구된다.

 

고효율성 Elasticsearch를 위한 솔루션


- 효율 적인 인덱스 디자인
인덱스를 설계하다보면 하나의 인덱스에 모든 데이터를 넣고 쿼리로 찾을것인지 아니면 여러 인덱스로 나눌것인지 고민된다. 어느것이 효율적이냐는 정답은 내가 사용하는 쿼리에 달려있다. 유형별로 사례를 보면서 확인해보자.

1. 쿼리에 filter가 들어가고 그 값이 Enumerable할 때는 인덱스를 나눠서 설계하라
만약 인덱스 내부에 데이터에서 지역별로 나눠서 데이터를 찾아야 한다면 다음과 같이 쿼리를 실행시킬 것이다. 이럴경우 지역별로 인덱스를 구분하여 만들면 더욱 효율적인 퍼포먼스를 기대할 수 있다.

{
    "query": {
        "bool": {
            "must": {
                "match": {
                    "title": "${title}"
                }
            },
            "filter": {
                "term": {
                    "region": "US"
                }
            }
        }
    }
}

 

2. 값이 enumerable하지 않다면 routing key를 사용하라.
만약 수백만개의 주문 데이터가 구매자별로 쌓인다고 가졍하였을때 구매자별로 인덱스를 구분한다면 너무 많은 인덱스를 구분해야한다. filter 사용되는 필드를 routing key로 사용하여 인덱스를 여러 shard로 쪼갤 수 있다. 그래서 이럴 경우 동일한 buyerId를 가지고 있는 데이터를 동일한 shard에 모여서 저장하면 모든 쿼리가 buyerId라는 routing key를 사용하여 한번에 조회되게 하면 퍼포먼스가 향상된다.

3. 기간이 정해져 있는 데이터들의 경우 기간별로 인덱스를 구성하여 사용하라.
로깅, 모니터링을 하는 데이터의 경우 일, 주, 월별로 데이터를 모을 수 있기 때문에 이를 사용하여 날짜별로 데이터를 모으면 더 빠르게 데이터에 접근할 수 있다.

4. mapping을 효율적으로 지정하라
인덱스에서 필드별로 mapping을 지정해줘야 해당 필드에 대한 검색이 가능하다. 기본적으로 데이터가 인덱스에 들어가면 기본적으로 자동 매핑을 해주지만 효율적이지는 않다. 그래서 정상적으로 인덱스에 맞게 효율적으로 인덱스를 설계하고 index생성시 dynamic옵션을 false로 지정하여 자동 매핑을 방지하는게 좋다. 자동매핑에 경우 문자열을 text, keyword모두 지정해주는데 이는 그닥 효율적이지 못한 대표적인 예이다.

5. 사용자 정의 id를 사용할 경우 불균형 샤딩에 대해 조심하라.
엘라스틱 서치는 자동으로 id를 생성해주는데 이를 호ㄹ용하여 적절하게 document들에 대하여 샤딩을 수행한다. 만약 사용자 지정 id를 사용하거나 별도의 routing key를 충분히 랜덤하지 않게 부여한다면 다른 shard들에 비해 특정 shard가 데이터가 많이 적재되는 문제를 초래할 수 있다. 이럴 경우 일기/쓰기가 굉장히 느려지게 되기 때문에 조심해야한다.

6. 여러 노드에 고르게 shard를 만들어라.
엘라스틱서치에는 coordinator node와 여러 마스터 노드들로 구성되어 있는데 coordinator 노드는 분배 역할을 주로 담당하고 master node들이 데이터 적재를 담당하는데 각 특정노드에 shard가 몰려있을 경우 전체 시스템의 bottle neck 현상이 발생할 수 있다.


7. bulk request를 높이고 refresh 기간을 올려라.
이벤트가 발생할 때마다 엘라스틱서치는 새로운 lucene segment를 만들고 그것을 추후에 합치는 작업을 진행한다. 이런 작업이 발생하는 주기가 refresh가 발생할 때 진행되는데 이런 문제를 줄이기 위해서는 refresh interval을 길게 잡아 놓으면 좋다. 하지만 refresh interval이 길면 변경된 데이터가 검색이 되지 않는다. 왜냐면 index가 refresh가 종료되어야 변경되거나 추가된 document가 검색에 잡히기 때문이다.


8. replica 수를 줄여라.
엘라스틱서치 노드는 주요 노드에 기록되고 모든 replica shard들에 인덱싱 요청이 발생된다. 그렇기 때문에 replica shard수가 많을수록 document의 인덱싱 속도가 현저하게 느려진다.


9. 가능하면 자동으로 생성되는 ID를 사용하라.
엘라스틱서치에서 만들어주는 ID는 고유값을 보증한다. 만약 사용자 고유 ID를 진행하고 싶은 경우 루신에 친화적인 zero-paddeded sequaltial 아이디인 UUID-1 또는 Nono time을 사용해야 한다. 이 아이디들은 일관되고 연속적인 패턴이 잘 압축되어 있는 형식들이다. 대조적으로 UUID-4는 완전하게 랜덤한값을 만들어내기 때문에 추천하지 않는다.


10. 가능하면 query context에 filter를 사용해라.
쿼리에서 찾고자 하는 값과 일치하는 걸 찾을 때 대부분인 yes or no로 찾을 수 있다. match등을 통해서 데이터를 찾으면 scoring이 들어가기 때문에 더 성능적으로 힘들어진다. 하지만 filter를 사용하면 결과가 캐시가 되는것뿐만 아니라 단순 yes or no이기 때문에 score 계산이 빠져서 더 효율적이다.


11. shard 노드를 효율적으로 관리하라
인덱스에 어느정도에 shard를 설정해야할까가 인덱스 구축시 고민을 많이 하게되는 요소이다. 불행하게도 모든 시나리오에 정확한 정답은 없다. 모든것은 어떻게 설계하냐에 따라 달려있다. 만약 너무 작은 수의 shard를 설정하게 되면 scale out이 되지 않는다. 예를들어 오직 하나의 shard만 있는 경우 모든 도큐먼트는 한곳에 저장되서 문제가 발생한다. 반대로 너무 많은 shard를 설정하게 되면 퍼포먼스에 문제가 발생한다. 왜냐하면 엘라스틱서치는 모든 shard에 쿼리를 실행시키기 때문에 request안에 routing key가 있다고 하더라도 fetch 그리고 merge가 모든 shard에서 나온 결과에서 발생하기 때문이다. 여러 관례로 봤을 때, 만약 index가 1G가보다 작으면 shard는 1개가 적당하다. 대부분에 경험상 shard를 5섯개를 기본으로 놓고 운영하는게 적당했다. 하지만 shard사이즈가 30GB가 넘으면 더 쪼개서 사용해야한다. 한번 생성된 index에 shard수를 조정하려면 reindex를 해야하므로 신중하길 바란다.


12. stop word를 사용한 검색을 자제하라
stop word는 a, the와 같이 검색 결과를 증가시키는 단어들이다. 만약 fox라고 검색하면 10건나올 데이터가 the fox라고 하면 the와 가까운 데이터가 출력되면서 거의 대부분의 document가 출력될 것이다. 엘라스틱서치는 모든결과를 score별로 정렬하기 때문에 the fox와 같이 stop word로 검색하면 전체 시스템을 느리게 만든다. 미리 token filter를 만들어서 stop word를 제거하고 검색되게 만드는게 효율적이다. 만약 당장 어렵다면 the ADN fox라고 검색해서 중요한 결과만을 뽑아낼 수 있다.

 

오랜만에 좋은글 잘 읽어서 기분이 좋다. 

출처 : https://www.ebayinc.com/stories/blogs/tech/elasticsearch-performance-tuning-practice-at-ebay/

반응형