팀 내 여러 파트에서 Elasticsearch를 활용하고 있습니다. 어플리케이션 레벨에서 데이터 조회 위한 코드를 작성하는 부분이야 계속 하다보면 늘겠지만 Elasticsearch 인프라에 관련된 부분에 대해서는 부족한 것 같아서 관련 내용을 정리하고 있습니다.
Nodes
Elasticsearch의 경우 여러 노드들을 모아 클러스터를 구성할 수 있습니다. 공식 문서에서는 클러스터가 커지고 변환이나 머신 러닝 등의 작업이 지속적으로 일어나는 경우 각각의 목적에 맞는 노드를 분리하는게 좋다고 설명하고 있습니다.
- Master-eligible node
- Data node
- Ingest node
- Remote-eligible node
- Machine learning node
- Transform node
모든 노드 타입을 살펴볼 필요는 없을 것 같아 주요한 몇가지 노드에 대한 내용만 살펴보겠습니다.
Master-eligible node
해당 노드로 지정되면 클러스터를 제어하는 마스터 노드로 선출 될 수 있습니다. 마스터 노드는 인덱스의 생성, 삭제 등 클러스터를 제어하는 역할을 수행합니다. 다수의 노드를 Master-eligible로 설정할 수 있지만 하나의 노드만 active master 역할을 수행합니다.
Dedicated, Voting Only 등 추가적인 설정도 있는 것 같지만 해당 내용은 생략합니다.
node.roles: [master]
Data node
데이터 노드에는 인덱싱된 도큐먼트가 포함된 샤드들이 위치합니다. 검색이나 집계 등 데이터 관련 작업을 처리합니다. I/O나 메모리 CPU를 많이 소모하는 작업들이 주로 실행되므로 리소스 모니터링 및 임계치 도달 시 데이터 노드를 추가해야 합니다.
전용 데이터 노드를 갖는 경우 마스터와 데이터 노드의 역할을 분리할 수 있습니다.
node.roles: [data]
Coordinating node
사용자 요청에 대해 로드밸런서 역할만을 수행하는 노드, 내부적으로 어떤 방식을 통해 부하를 분산시켜주는지는 별도로 찾아봐야 하겠지만 클러스터 전체의 부하가 큰 경우라면 별도로 Coordinating 노드를 가지는 편이 좋을 것 같습니다.
- Coordinating node가 너무 클러스터에 많이 추가되면 전체 클러스터에 대한 부담이 증가할 수 있습니다.
node.roles: []
Ingest node
데이터 색인을 위한 전처리를 담당하는 노드입니다. 현재 별도로 Ingest 노드를 분리할 필요는 없어보이는데, 이후 사용이 필요한 시점에 어떤 방법으로 전처리를 수행하는지 파악해보면 좋을 것 같습니다.
node.roles: [ingest]
Index
Elasticsearch에서 저장된 한 Row를 Document라고 하며 이 Document들의 집합을 Index라고 합니다.
인덱스는 클러스터 내의 여러 데이터 노드에 Shard라는 이름으로 분산되어 저장됩니다.
Index Template을 정의해 Elasticsearch에서 인덱스를 구성하는 방법을 미리 정의할 수 있습니다. 관련 자세한 내용은 위 링크를 참고합니다.
Index Template이 설정되어 있지 않으면 자동으로 필드 생성 및 타입을 결정해 예기치 않은 문제를 야기할 수 있습니다.
PUT _index_template/template_1
{
"index_patterns": ["te*", "bar*"],
"template": {
"settings": {
"number_of_shards": 3,
"number_of_replicas": 1
},
"mappings": {
"_source": {
"enabled": true
},
"properties": {
"host_name": {
"type": "keyword"
},
"created_at": {
"type": "date",
"format": "EEE MMM dd HH:mm:ss Z yyyy"
}
}
},
"aliases": {
"mydata": { }
}
},
"priority": 500,
"composed_of": ["component_template1", "runtime_component_template"],
"version": 3,
"_meta": {
"description": "my custom"
}
}
Shard
인덱스 내부에 색인된 데이터들은 여러 노드에 여러 파티션으로 나누어서 저장되는데 이 나누어진 각각의 파티션들을 Elasticsearch에서는 Shard라고 부릅니다.
7.0 버전 이후 기준으로 인덱스 생성 시 디폴트로 1개의 샤드가 구성되며 만약 샤드 개수를 지정하고 싶으면 Index Template을 생성해야 합니다.
클러스터 내 2개의 데이터 노드를 가진 상태에서 6개의 프라이머리 샤드, 1개의 레플리카 샤드를 지정한 인덱스를 생성하면 아래와 같은 형태로 배치되게 됩니다.
- 2 Data Node, 6 Primary Shard, 1 Replica Shard
Segment
인덱스 내부의 문서들은 여러 샤드에 나뉘어 저장되며, 각각의 샤드들은 한개 이상의 세그먼트로 구성되어 있습니다. 세그먼트 내부에는 실제 문서 데이터가 저장됩니다.
세그먼트는 불변의 특성을 가집니다. 따라서 문서를 삭제하거나 동일한 아이디로 다시 인덱싱을 하는 경우 세그먼트를 업데이트 하는게 아니라 기존 세그먼트를 비활성 상태로 두고 새로운 세그먼트를 생성합니다.
세그먼트가 쌓이면 디스크, 검색 속도와 관련된 문제가 생길 수 있습니다. 이러한 문제를 해결하기 위해 엘라스틱서치는 내부의 Scheduler를 통해 세그먼트 병합을 수행합니다. 상황에 따라 스케줄링을 기다리지 않고 Force merge를 수행할 수 있습니다.
세그먼트를 병합하면 디스크가 확보되며, 검색 요청 시 접근해야하는 파일의 수가 줄어들어 검색 요청에 대한 부하가 적어지게 됩니다.
Reference
https://www.elastic.co/guide/en/elasticsearch/reference/current/index-templates.html