개발블로그

[번역글] ElasticSearch에 대해 알아야 할 6가지 본문

ElasticSearch

[번역글] ElasticSearch에 대해 알아야 할 6가지

개발자수니 2019. 4. 15. 22:58

재직중인 부서에서는 데이터 시각화를 위해 엘라스틱서치(ElasticSearch)를 이용하고 있습니다. 많은 시행착오 과정에서  6 not so obvious things about Elasticsearch라는 글이 도움이 되었습니다. 이를 번역해 공유합니다.


엘라스틱서치는 다양한 분야에서 채택된 검색엔진으로, Netflix, Microsoft, Facebook등 유수의 기업들도 사용하고 있습니다. 일반적으로 초기 진입장벽이 낮으나, 장기적으로 이용하고 마스터하기에는 다소 어렵다고 평가받고 있습니다.

그래서 지금부터 엘라스틱서치를 시스템에 적용하기 전에 알고 있으면 좋은, 여섯 가지 다소 모호한 것들에 대해 설명하겠습니다. 

1. ElasticStack

2. Two Kinds of data sets

3. Search score

4. Data model

5. Shards planning

6. Node types


1. ElasticStack

엘라스틱서치의 초기 모델은  '모든 언어에서 사용가능하고 확장가능한 검색엔진' 이었습니다. 따라서 확장성을 위해 엘라스틱서치 내부는 분산 모델로 개발되었고, REST API를 통해 엘라스틱서치에 조회/저장 등의 작업을 할 수 있도록 구현했습니다. 

 

엘라스틱서치를 출시한 이후, 엘라스틱서치와 함께 이용할 수 있는 툴들이 개발되었는데 예를 들어 Kibana,  Logstash 등이 있습니다. 

- ElasticSearch - 검색을 위한 도구.

- Kibana - 데이터 분석 및 시각화를 위한 도구.

- Logstash : 서버측 데이터 파이프라인. 외부에서 Logstash로 데이터를 실시간으로 전송할 수 있도록 합니다. 또한 Logstash는 전달받은 데이터를 ElasticSearch에 저장하거나 가공할 수 있습니다. 

- beats : 데이터를 전송하는 도구.  예를 들어, Beats의 종류 중 Filebeats는 지정한 File에 쌓이는 데이터를 실시간으로 Logstash에 전송할 수 있습니다.

- Elastic Cloud - 엘라스틱서치 클러스터들을 호스팅합니다.

- Machine Learning - 엘라스틱서치에 저장되는 데이터들의 패턴을 탐색하기 위한 도구.

- APM - 어플리케이션의 성능을 모니터링하기 위한 도구.

- Swiftype - 사이트 내 검색을 위한 도구.


2. Two kinds of data sets

엘라스틱서치에는 원하는 모든 데이터를 색인(저장)할 수 있습니다. 그리고 그 데이터의 타입(정적 데이터, 시계열 데이터)에 따라 클러스터가 어떻게 구성되고 관리되어야 하는지가 결정됩니다. 

 

정적 데이터는 카탈로그나 상품의 재고처럼 천천히 증가하거나 변화하는 데이터셋입니다. 블로그 포스트, 도서관의 책, 주문 등 일반적인 데이터베이스에 저장하는 데이터와 비슷합니다. 일반 SQL 데이터베이스에 저장/조회해도 무관하지만, 엘라스틱서치를 이용한다면 더 빠른 검색이 가능해집니다.

우리는 시계열 데이터도 엘라스틱서치에 저장할 수 있습니다. 시계열 데이터란 로그파일이나 지표와 같이 빠르게 흘러가는 시간의 특정 순간에 일어난 이벤트의 데이터입니다. 일반적으로 이런 시계열 데이터는 데이터 분석, 패턴탐색, 시스템 모니터링을 위해 엘라스틱서치에 색인됩니다.

 

저장하고자 하는 데이터가 정적 데이터인지 시계열 데이터인지에 따라 클러스터를 다르게 구성해야 합니다. 정적 데이터의 경우 고정된 인덱스/샤드를 선택해야하는데, 그 이유는 데이터량이 빠르게 늘어나지 않거니와 검색 시 모든 다큐먼트를 참조할 것이기 때문입니다.

시계열 데이터의 경우, 시간 이동 롤링 인덱스를 선택해야합니다. 일반적으로 시계열 데이터에 대해서는 최근 데이터를 위주로 조회하므로 비용을 절감하기 위해 오래된 데이터는 영구적으로 지우거나 다른 저장소에 백업하기 때문입니다.


3. Search score

이 글의 1절에 언급했다시피, 엘라스틱서치의 주된 목적은 검색 엔진을 제공하는 것입니다. 다시 말해 특정 키워드로 검색을 하면, 그 키워드가 포함된 가장 적합한 다큐먼트를 반환하는 것이 목적입니다. 엘라스틱서치가 어떻게 가장 적합한 다큐먼트를 찾을까요?

 

모든 검색어에 대해 엘라스틱서치는 상대적인 점수를 계산하는데, 그 점수는 TF-IDF(Term Frequency - Inverse Document Frequency) 알고리즘에 기반합니다. 이 알고리즘을 통해 TF, IDF 값을 알아낼 수 있는데, TF는 검색어가 하나의 다큐먼트에서 얼마나 자주 사용되는지를 나타내는 지표이고  IDF는 검색어가 모든 다큐먼트를 통틀어 얼마나 유니크한지를 나타내는 지표입니다.

 

예를 들어, 다음 두 개의 다큐먼트가 있다고 가정해봅시다. 

1) To be or not to be, that is the question.

2) To be. I am. You are. He, she is.

 

question이라는 키워드에 대해 TF를 구해보겠습니다.

다큐먼트1: 10개의 단어 개수 중 question과 일치하는 단어는 1개 있으므로 1/10 입니다.

다큐먼트2: 9개의 단어 개수 중 question과 일치하는 단어는 없으므로 0입니다.

 

반면 IDF는 전체 데이터셋에 대해 단일 값으로 계산됩니다.

IDF는 [question을 포함하고 있는 문서:모든 문서]의 비이며 위의 예제의 경우 다음과 같은 결과가 도출됩니다.

log(2/1) = 0.301

 

결과적으로 두 문서에 대한 TF-IDF점수는 다음과 같습니다.

다큐먼트1 : 1/10 * 0.301 = 0.1 * 0.301 = 0.03

다큐먼트2 : 0/9 * 0.301 = 0 * 0.301 = 0

 

이러한 계산을 통해서 question이라는 단어에 대해 다큐먼트1은 0.03만큼 연관이 있고, 다큐먼트2는 0만큼 연관이 있다고 판단합니다.

그러므로 다큐먼트1이 결과 리스트에서 더 우위에 노출됩니다.


4. Data model

엘라스틱서치는 성능의 관점에서 두가지 이점을 가지고 있습니다. 수평적으로 확장가능하고 매우 빠르다는 것입니다. 어떻게 엘라스틱서치는 속도를 빠르게 할 수 있었을까요? 그 비결은 데이터를 저장하는 방법에 있습니다.

 

다큐먼트를 저장할 때, 내부적으로 3가지 단계를 거치게 되는데, 이 단계를 통해 다큐먼트가 정규화됩니다.

-character filter: html 요소 제거, 마침표 제거 등

-tokenizer : 단어 쪼개기 등

-token filter : 토큰의 소문자화 등

 

예를 들어, 다음과 같은 다큐먼트가 있다고 가정해봅시다.

To be or not to be, that is the question.

정규화 과정을 거치면, 마침표가 제거되고 소문자로 변경되어 다음과 같이 저장될 것입니다.

to be or not to be that is the question

 

여기서 끝이 아닙니다.

만약 stop token filter(token filter의 일종)가 적용된다면 다음과 같이 저장될 것입니다.

question

stop token filter는 to, be, or, not, that, is the.와 같은 일반적인 용어들을 모두 제거하는 역할을 합니다.

 

위의 정규화 과정을 거쳐 도출된 question이 인덱싱을 위한 key가 됩니다. 이 정보는 다음과 같이 inverted index구조로 저장됩니다.

terms(=key) document ids
question 1

 

그리고 다큐먼트에 대해 검색을 할 때도, 위 단계들을 적용한 정규화된 용어로 문서를 찾습니다.

예를 들어 검색 키워드를 'to question' 이라고 했을 때, 정규화 과정을 거치면 question으로 변환됩니다. 그리고 question을 key로 가지는 다큐먼트를 찾습니다.

 

인덱스 내의 각각의 필드마다 하나 이상의 필터를 정의할 수 있는데, 이 필터들의 집합을 analyzer라고 칭합니다. 또한 하나의 필드는 많은 analyzer로 분석할 수도 있습니다.

상황에 따라 영어 analyzer 혹은 한국어 analyzer로 분석할 수 있게 되는 것입니다. 이는 검색 단계에서 analyzer를 정의하기 때문에 가능합니다.

 

엘라스틱서치는 위와 같이 다큐먼트를 정규화한 값을 inverted index로 저장/검색하기에 일반 데이터베이스를 이용할 때보다 속도가 빠릅니다.


5. Shards planning

엘라스틱서치를 이제 막 입문한 사람들에게 자주 듣는 질문은 "샤드와 인덱스의 갯수를 얼마나 많이 설정해야할까요?" 입니다. 왜 이런 질문이 나올까요?

인덱스 생성할 때만 샤드의 갯수를 설정할 수 있기 때문입니다.

 

결론적으로는 샤드와 인덱스의 갯수는 보유한 데이터셋에 따라 다르게 설정해야 합니다. 이를 위해 염두해 두어야 할 것은 각각의 샤드를 20-40GB(Elastic 전문가들이 추천한 크기)의 데이터로 구성해야 한다는 것입니다. 샤드는 아파치 루신에서 비롯됐는데, 엘라스틱 서치가 아파치 루신을 내부적으로 사용합니다. 아파치 루신이 inverted indices와 빠른 검색을 위해 사용한 오버헤드와 모든 구조를 염두해보면, 샤드를 추천 크기 이하의 데이터로 구성하는 것은 무리가 있습니다. 

 

왜 Elastic 전문가들은 샤드를 20-40GB로 구성하라고 추천할까요? 

샤드는 더이상 나눌 수 없고 항상 단독 노드로 존재합니다. 클러스터 내에서 샤드가 추가되어야 하는 상황이 생기면 20-40GB로 샤드를 구성했을 때, 보다 쉽게 다른 노드로 이동되거나 복제될 수도 있으므로 샤드의 용량을 20-40GB로 추천합니다. 즉 속도와 메모리 소비간에 최적의 균형을 맞출 수 있는 용량이라는 것입니다. 하지만 이 수치는 추천일 뿐이므로 필요에 따라 다르게 구성할 수도 있습니다. 

 

그럼 하나의 인덱스당 얼마나 많은 샤드를 두어야 할까요?

이는 간단한 측정을 통해 알 수 있습니다. 하나의 임시 인덱스로 많은 다큐먼트를 인덱싱합니다. 그 후 얼마나 많은 메모리가 소비되는지, 시계열 데이터라면 일정 시간동안 얼마나 많은 다큐먼트가 인덱싱 되는지, 정적 데이터라면 전체 시간동안 얼마나 많은 다큐먼트가 인덱싱 되는지를 살펴봅니다. (측정한 다큐먼트 용량에서 각각의 샤드 용량을 나누면, 하나의 인덱스당 샤드를 몇개 두어야 할지 알 수 있습니다.)

 

만약 샤드나 인덱스의 수를 잘못구성했다면, 샤드의 갯수를 다르게 조정해 리인덱싱할 수 있습니다.

그리고 한번에 여러개의 인덱스에 대해 쿼리할 수도 있습니다. 예를 들어, 날짜별로 로그 데이터에 대해 인덱스를 생성했다면, 하나의 쿼리로 지난 한달동안의 인덱스에 대해 질의를 할 수도 있습니다. 참고로 각각 1개의 샤드로 구성된 30개의 인덱스에 조회하는 것은 30개의 샤드로 구성된 1개의 인덱스에 조회하는 것과 같은 성능을 냅니다.


6. Node Types

하나의 엘라스틱서치 노드는 다양한 역할을 합니다. 하나의 노드에서 몇 가지의 역할을 수행시킬지는 설정하기 나름이지만, 아무런 설정을 해주지 않는다면 모든 역할을 수행합니다. 그리고 이것은 소규모 클러스터에 적합합니다. 이 절에서는 각각의 역할에 대해 다루려고 합니다.

-master node

마스터노드는 클러스터 전반의 세팅과 변화에 대해 책임지며 인덱스를 생성/삭제한다거나 노드를 추가/삭제한다거나 노드에 샤드를 할당하는 등의 역할을 합니다. 

모든 클러스터는 적어도 3개의 마스터 후보 노드(마스터가 될 가능성이 있는 노드)를 구성해야하고, 사실 그 이상의 갯수는 필요 없습니다.  모든 마스터 후보 노드 중 하나가 마스터노드가 되며, 그것의 역할은 클러스터 전반의 관리를 수행하는 것입니다. 다른 마스터 후보 노드들은 고가용성을 위해 필요합니다. 마스터노드를 동작시키기 위해서는 낮은 사양의 CPU, RAM, disk storage가 적합합니다.

-data node

데이터노드는 데이터를 저장하고 탐색하는데 사용되므로 높은 사양이 필요합니다. 데이터량이 많을수록 사양은 높아야 합니다.

-ingest node

실제 인덱싱이 일어나기 전, 다큐먼트를 전처리하는데 사용합니다. 대량의 쿼리, 인덱스 쿼리를 가로채 변환하고, 다시 그 다큐먼트를 index/bulk api로 전달합니다. disk사양은 낮아도되지만, ram은 어느정도 사양이 갖춰져야하며, 계산이 많으므로 높은 사양의 CPU를 요구합니다.

-coordinating-only node

이 노드는 클라이언트 요청을 위한 것으로, 로드밸런서로서의 역할을 합니다. 그들은 다큐먼트가 명확히 어디에 있는지 알기에, 이 노드들에게만 검색 요청을 할 수 있습니다.  그 후 이 노드들은 받은 결과에 대해 scatter&gather를 수행합니다. disk 사양은 낮아도 되고 ram, cpu는 어느정도 사양이 갖춰져야 합니다.

 

각 노드들은 위에 나열된 노드의 역할 중 하나 이상의 역할을 수행할 수 있습니다. coordination role은 모든 노드에 의해서 수행됩니다. coordination-only node로만 가지기 위해서는 다른 롤에 대해 disabled처리를 해야합니다.

 

 

이러한 정보들을 알게 되면, 큰 클러스터링을 구성하기 위해 어떻게 해야하는지 궁금할 것입니다. 아래와 같은 구성을 추천합니다.

1. 3개의 마스터노드

2. 몇 개의 coordination only nodes

3. 많은 data node - 데이터 량에 따라 갯수를 조정합니다.

4. 몇 개의 ingest node - ingest pipeline을 수행하고, 다른 노드에게 전처리 부담을 주지 않기 위해서 사용합니다.

 

구체적인 node 수 선택은 상황에 따라 다릅니다.

Comments