ElasticSearch index 적정 샤드 결정하기

2019. 10. 29. 12:19Datasources/elasticsearch

배경

- 팀에서  storage 의 확장성을 위해 main data source 로 Cassandra 를 채택하였다. Cassandra 는 Scalable 하지만 multiple query pattern 을 수용하기에 적합하지 않다. 그래서 inverted index 로 ElasticSearch 를 채택하였다. 요즘 나오는 솔루션들을 볼때마다 생각하지만 인터페이스가 참 좋다. ES 역시도 REST API 로 ES 의 사용법을 익히고 사용하는 것은 아주 쉽다.

 

사용법을 충분히 숙지한 후 아래의 고민들이 스멀스멀 올라왔다.

- 클러스터가 일시적으로 다운된다면 어떻게 recovery 할 것인가?

- index 의 성능이 대고객 서비스를 제공하기에 충분히 빠르지 않는다면 어떻게 시스템 중단 없이 복구할 것인가?

- ES cluster 스펙은 어느정도가 적절한가?

- cluster 스펙 내에서 적정한 샤드와 레플리카의 수는 어떻게 결정할 것인가?

 

다행히도 현재 머릿속에서 대부분의 고민들은 해결되었고 그 중 마지막

cluster 스펙 내에서 적정한 샤드와 레플리카의 수는 어떻게 결정할 것인가? 부분을 한번 정리하고 넘어가려 한다.

 

# of shards, 그 이전에..

- 엘라스틱 서치는 내부적으로 루씬을 통해 검색기능을 수행한다. 

클러스터 관점에서 구성요소 (Terms)

- 클러스터(Cluster): 데이터를 실제로 가지고 있는 노드의 모음. 같은 클러스터 내부의 데이터만 서로 공유가 가능

- 노드(Node): 물리적으로 실행된 runtime 상태의 엘라스틱서치, 즉 논리적인 클러스터를 이루는 구성원의 일부이며 데이터를 물리적으로 가지고 있는 단일서버이다. 실행시 Cluster에 의해 uuid 를 할당하고 uuid 로 노드 서로를 식별한다. 노드는 내부에 다수의 index 를 가지고 있으며 각 index 는 다수의 document 를 가지고 있다. "indexing" 작업을 통해 데이터는 엘라스틱 서치에 document 형태로 저장된다.

    노드의 형태 

    -Master Node: node.master 의 설정이 true 인 노드이다. 클러스터의 제어를 담당한다.

    -Data Node: node.data 의 설정이 true, 데이터를 보유하고 CRUD, SEARCH, AGGREGATION 등을 담당한다.

    -Ingest Node: node.ingest 가 true 로 설정된 노드다. index preprocessing 을 담당한다.

    -Coordinating Node: Search 나 aggregation 시 분산 처리만을 목적으로 설정된 노드다. 대량의 데이터를 처리할 경우 효율적일 수 있다.

- 인덱스(index, 색인) : Collection of document, 현재는 index : type = 1 : 1 이다.

- 문서 (document) : 인덱스는 원하는 만큼의 많은 문서를 저장할 수 있으며 실제로는 물리적인 샤드 형태로 나뉘어져 다수의 노드로 분산 저장된다.

- 샤드(shard) : 하나의 하드웨어에서 제공되는 리소스 이상의 데이터를 제공하기 위한 개념. 이를 이용하여 손쉬운 scale-out 이 가능하다

 이 포스팅의 핵심인데, 엘라스틱 서치에서는 인덱스를 생성하는 경우 기본적으로 5개의 샤드로 데이터가 분산되도록 한다(변경가능하다). 하나의 샤드는 인덱스의 부분집합이지만 하나의 샤드 내에서도 검색은 가능하다.

- 레플리카(Replica): 샤드의 복제본, 기본은 1개, 검색시 레플리카도 활용되기 때문에 읽기 분산에 도움이 된다. 가장 큰 장점은 Failover 이다. 특정노드에 장애가 온 경우에 primary shard 를 대신하여 서비스 된다. (즉 replica 와 원본 샤드는 동일 노드에 존재하지 않는다/ 해선 안된다.)

- 세그먼트(Segment): 문서들을 빠른 검색에 유리하도록 설계된 특수한 자료구조, 샤드 내부에는 루씬 라이브러리가 포함되어있는데, 이를 이용해 검색이 제공된다. 루씬에 데이터가 indexing 되면 데이터는 최소한의 단위인 토큰으로 분리되고 특수한 형태의 자료구조로 저장되는데 이렇게 저장된 자료구조를 segment 라고 한다. 

또한 세그먼트는 불변성을 가진다. 즉 한번 생성된 segment 는 변경이 불가능하다. 이 덕분에 아래의 이점들을 얻는다.

- 동시성 문제 회피

- 시스템 캐시를 적극적으로 활용 / higher cache rate

- save resource

 

전체 구조

index
ES shard ES shard ES shard ES shard
Lucene index Lucene index Lucene index Lucene index
segment segment segment segment segment segment segment segment

물론 샤드가 단순히 루씬 그 자체만은 아니다. 샤드 내부적으로 ES 에서 추가한 다양한 기능이 포함되어있다. 하지만 본질이 루씬 인덱스라는 사실은 변함이 없다. 즉 샤드는 가장 작은 단위의 단일 검색엔진이다.

다시말해  엘라스틱 서치는 루씬 인덱스를 샤드로 확장해서 제공하는 것이고 이를 이용해 수평적 확장의 이점을 가져갔다.

 

서비스를 운영하다보면 시간이 지남에 따라 데이터의 크기는 점점 더 커지고 그에 비례해서 성능상의 문제가 발생할 가능성 또한 커진다.(실제로 유관팀에서 인덱스 팽창으로 인한 치명적 장애가 생겨 야근을 한 경험이 있다 ㅜㅜ) 클러스터에 저장된 데이터가 많아질수록 문제가 발생한 경우 이를 해결하는 것도 어려워진다.

클러스터의 성능 문제가 발생하면 샤드 수에 대한 고민을 다시 하게 되는데 샤드는 운영 중에 변경이 불가능하다.(reindexing 해야한다) 그러므로 샤드 수를 신중하게 결정하도록 하자.

 

# 본론

왜 운영중에 샤드 수를 늘리거나 줄이지 못하는 것인가?

- 각 샤드는 내부에 독립적인 루씬라이브러리를 가지고 있고 루씬은 단일 머신(stand alone) 위에서 동작하는 검색엔진이다.

이러한 특징 때문에 샤드 내부의 루씬 입장에서는 다른 샤드의 존재를 모른다. 모든 샤드는 자신의 검색결과를 돌려줄 뿐이다.

5샤드에 1억건의 데이터라고 하면 2000만건을 가지고 있는 독립적인 5개의 검색엔진이 운용되는 것이다.

샤드를 늘린다는건 독립적인 루씬이 가지고 있는 데이터들을 모두 재조정한다는 의미이다. 세그먼트는 원칙적으로 변경이 불가능하기 때문에 이는 불가능하다. (reindex API 를 활용하자)

 

레플리카 수는 얼마가 적정한가?

- 레플리카 샤드의 수는 운영중에도 얼마든지 변경할 수있다.

- 일반적으로 장애가 발생했을때 빠른 복구를 위해 1개 이상의 replica 를 사용하자. 레플리카 샤드 역시도 내부적으로 루씬을 가지고 있으므로 샤드수가 많은 경우 검색 속도는 빨라질 수 있지만, indexing 속도의 저하를 겪을수 있다. # of replica option 을 1~2로 주고 운영중에 변경을 하는 형태가 좋을 것으로 생각된다.

 

클러스터에 많은 수의 샤드가 존재할 경우?

클러스터에 존재하는 모든 샤드는 마스터 노드에서 관리된다. 이말은 즉슨 샤드가 많아질수록 마스터 노드의 부하도 덩달아서 증가한다는 뜻이다. 마스터 노드가 처리해야 하는 정보가 많아지면 검색이나 색인같은 작업도 덩달아 느려질 수 있다. 또한 마스터 노드의 메모리 사용량도 덩달아 늘어난다. 마스터 노드는 성능 향상을 위해 샤드 정보와 같은 관리 데이터를 모두 메모리에 올려서 사용하기 때문이다. 특히나 마스터 노드의 다운은 클러스터 전체의 다운으로 이어지기 때문에 주의해야 한다.

 

샤드의 물리적인 크기와 복구시간

마스터 노드의 입장에서는 샤드가 가지고 있는 데이터의 건수보다 데이터의 물리적 크기가 중요하다. 마스터노드는 장애시 샤드 단위로 복구를 수행하기 때문이다.

일단 노드에 장애가 발생하면 프라이머리와 동일한 데이터를 가지고 있는 레플리카 샤드가 순간적으로 프라이머리 샤드로 전환되어 서비스된다. 그와 동시에 프라이머리로 전환된 샤드의 레플리카가 다른 노드에서 새로 생성된다. 시간이 지나 장애가 복구되면 복구된 노드로 일부 샤드들이 네트워크를 통해 이동한다. 시간이 지남에 따라 클러스터에 균형이 맞추어진다.

이러한 프로세스가 있기때문에 단일 샤드의 물리적 크기가 크다면 recovery 가 신속히 이루어지지 못할 위험이 있다.

 

그렇다면 적절한 샤드의 크기는?

하나의 샤드 크기에 대해 특별히 정해진 공식은 없지만 여러 엘라스틱 서치 관련 포스팅이나 공식 문서에서 50GB 를 넘지 않고 수 GB 에서 40GB 정도를 권장하고 있다.

 

필자는 이를 위해 데이터 적재의 추이를 파악해 일단위/주단위/월단위 인덱스를 사용하길 제안한다.

alias 와 index template 를 활용하여 인덱스를 나누었을때 조회문제 인덱스 생성문제를 해결할 수 있다

 

아래의 예를 보자

1. 인덱스가 큰 데이터(400GB 이상)을 가지는 경우

case 1 '2개의 샤드') 하나의 샤드가 200GB 일 것, 이 경우 복구를 위한 네트워크 비용이 지나치게 많이 발생한다./

case 2. 400개의 샤드) 복구 비용은 아주 저렴하겠지만 마스터 노드는 많은 샤드정보를 관리해야 하기에 부하와 리소스 낭비를 가져오게 된다.

2. 인덱스가 작은 데이터(1GB) 를 가지는 경우.

case 1 기본 옵션 5개) 권장한다.

case 2 100개의 샤드로 분산저장하는 경우) 하나의 샤드는 10MB 의 크기를 가질것이다. 마스터노드.. ㅠㅠ

 

또한 클러스터 내에 데이터가 급증하거나, 검색쿼리의 유형이나 집계의 규모등 고려하야 할 사항이 더 있다.

좋은 글을 첨부해둔다 아래 링크 중
https://www.elastic.co/blog/how-many-shards-should-i-have-in-my-elasticsearch-cluster 를 확인하길 바란다.

검색쿼리 관점에서 이야기 해보자.  샤드의 수가 적으면 하나의 샤드에서 읽어야할 데이터가 많기 때문에 단일 쿼리의 응답 속도는 떨어질 것이다. 하지만 해당 노드의 Thread 풀은 상대적으로 여유로울 것이므로 대량의 쿼리가 인입되는 경우 상대적으로 고른 성능을 보장할 수 있다. 반대로 샤드의 수가 많은 경우 단일 쿼리의 성능은 빠를 수 있지만 대량의 쿼리가 인입될 경우 스레드 풀이 고갈되어 쿼리별 성능의 편차가 고르지 않을 수 있다.

 

결론

가장 좋은 방법은 아쉽지만 직접 실 데이터를 사용해 충분한 테스트를 해보는 것이라고 생각한다. 실버 불릿은 없다..ㅠㅠ

 

덧붙이는말

- recovery 전략과 실 운영환경에서의 인덱스 구성에 대한 포스팅을 한번 더 하려합니당.

 

 

참고

- 엘라스틱서치 실무가이드 위키북스

- https://www.elastic.co/kr/blog/how-many-shards-should-i-have-in-my-elasticsearch-cluster

 

How many shards should I have in my Elasticsearch cluster?

이 블로그는 여러분의 클러스터에 적합한 인덱스와 샤드의 개수와 크기를 어떻게 가져가야 하는지에 대한 실질적인 가이드라인을 제공합니다.

www.elastic.co

https://www.elastic.co/blog/how-many-shards-should-i-have-in-my-elasticsearch-cluster

 

How many shards should I have in my Elasticsearch cluster?

이 블로그는 여러분의 클러스터에 적합한 인덱스와 샤드의 개수와 크기를 어떻게 가져가야 하는지에 대한 실질적인 가이드라인을 제공합니다.

www.elastic.co

- https://brunch.co.kr/@alden/39

 

클러스터 설계하기 - #1 검색 성능과 샤드 개수

ElasticSearch | 이번 글에서는 ElasticSearch (이하 ES)의 클러스터를 설계하기 위해 필요한 요소들 중 샤드의 개수가 검색 성능에 미치는 영향을 바탕으로 적정한 샤드의 개수와 데이터 노드의 개수를 산정하는 방법에 대해 이야기해 보려고 합니다. ES는 대부분의 경우 기본 설정 만으로도 충분한 성능을 보여 주지만 서비스에 투입하기 위한 검색 엔진으로 사용하거나 대용

brunch.co.kr