Elasticsearch Cluster 구조
- Elasticsearch는 분산형 검색 엔진으로써 데이터를 여러 노드에 분산해서 저장
- 각 노드는 여러 개의 인덱스를 가질 수 있으며
- 각 인덱스는 여러 개의 샤드로 구성
- 샤드는 primary 샤드와 replica 샤드로 구성
- 샤드는 Apache Lucene 인스턴스로써 독립적으로 작동하며 각 샤드는 데이터의 일부분을 가지고 있음

검색 요청의 처리 과정
- Elasticsearch의 검색 요청은 크게 두 단계로 나뉨
- Query phase
- Fetch phase
- 이 때문에 query then fetch라고도 불림
1. Query Phase
- 검색 요청이 수행되어야 하는 샤드를 결정하고 각 샤드에서 검색을 수행하는 단계
- client 요청은 L4 등을 통해 특정 노드로 라우팅
- 요청을 받은 노드는 인덱스의 데이터를 가지고 있는 전체 샤드에 broadcasting
- 요청을 받은 샤드는 각 샤드 내에서 쿼리를 수행
- 각 샤드는 매칭이 되는 문서의 id와 score 값을 반환
- coordinating node는 각 샤드로부터 반환된 결과를 모아 가장 점수가 높은 문서들을 선별
2. Fetch Phase
- Query Phase에서 선별된 문서들의 실제 내용을 가져오는 단계
- coordinating node는 Query Phase에서 선별한 내용을 기반으로 각 샤드에게 해당 문서들의 실제 내용을 요청
- 각 샤드는 요청받은 문서의 내용을 반환
- coordinating node는 이들 문서를 모아 최종적인 검색 결과를 생성

부연 설명
- 두 단계로 분리함에 따라 Query Phase에서는 가능한 한 적은 양의 데이터만 처리하여 네트워크 트래픽과 메모리 사용량을 최소화
- 실제로 필요한 문서의 내용만 Fetch Phase에서 가져와서 처리 효율을 높임
- score 계산은 개별 샤드에서 수행
- 하지만 일반적인 BM25 알고리즘에서 보면 TF는 문서 내에서 계산이 가능하지만 IDF는 전체 문서의 정보를 알아야지만 계산이 가능
- 그러나 IDF를 글로벌하게 계산하면 리소스가 많이 들기 때문에 일반적으로는 수행하지 않음
- 그리고 데이터가 충분하고 문서가 샤드마다 잘 분산이 되어 있을 경우 로컬에서도 거의 동일한 값으로 계산이 되기 때문에 문제없음
- 성능 저하를 유발하더라도 매우 정확하게 계산해야 할 경우 글로벌하게 계산할 수 있는 옵션 제공
GET <인덱스>/_search?search_type=dfs_query_then_fetch
주의할 점
- query then fetch 과정에서 from, size를 사용해서 검색을 하는 경우 뒷 페이지를 검색할수록 각 샤드에서 가져오는 데이터의 양이 많아질 수밖에 없으며 각 샤드에서 가져올 문서들을 정렬하는데도 리소스가 많이 들어감
- 샤드 개수 * (from + size)
검색 요청에서 샤드 특징 및 최적 샤드 갯수
1. Primary & Replica Shard
- Primary 샤드와 해당하는 Replica 샤드는 같은 데이터를 가지고 있고 이를 통해 데이터의 안전성 및 가용성을 보장
- 검색 요청 처리 시 Elasticsearch는 기본적으로 사용 가능한 모든 Primary와 Replica 샤드 중에서 하나를 선택하여 요청을 처리
- Round Robin 방식으로 이루어지며 이를 통해 검색 요청의 부하를 분산
1.1 Adaptive Replica Selection(ARS)
- Round Robin 방식의 허점을 보완하는 방식
- 기존의 라운드 로빈 방식과 비교하여, ARS는 각 요청에 대해 더 나은 복제본을 선택함으로써 성능을 최적화
- ARS는 단순한 라운드 로빈 방식 대신, 각 복제본의 현재 상태와 성능을 고려하여 더 적합한 복제본을 선택하며 주요 요소는 다음과 같음
- 응답 시간(latency): 각 복제본의 평균 응답 시간을 모니터링하며 응답 시간이 빠른 복제본을 우선적으로 선택
- 큐 길이(queue length): 각 복제본이 처리 중인 요청 수를 확인하며 요청이 덜 쌓인 복제본을 선택하여 과부하를 방지
- 노드 상태: 복제본이 있는 노드의 상태(CPU 사용률, 메모리 상태)를 고려
2. 최적 샤드 갯수
- 샤드 갯수 선정 시 여러 요소를 고려해야 함
- 검색 목적
- 문서 수
- 검색량
- aggregation 사용 여부
- 인덱스 갯수
- etc.
2.1 Primary 샤드 갯수 선정
- 자원을 효율적으로 쓰기 위해서는 노는 노드가 없도록 샤드 개수를 분배하는 것이 필요
- 하나의 샤드가 처리 가능한 max 사이즈 산정
- 429 에러가 발생하는 것을 확인해 보면서 색인이 얼마나 가능한지 파악
- 보통 검색 서비스 샤드는 20GB, 로깅 플랫폼 샤드는 50GB 권장
- 로깅 플랫폼의 경우 인덱스 사이즈가 커지면 롤링을 통해 인덱스 새로 만드는 것이 답일 수도 있음
2.2 Replica 샤드 개수 선정
- 우선 1개로 시작
- 많으면 안정화와 검색 성능에 도움이 되지만 너무 많을 경우 색인 성능이 저하되고 디스크 사용량이 많아짐
score가 계산되는 과정과 순서
1. score 값에 영향을 주는 요소
- TF-IDF 점수: 검색 쿼리에서의 각 단어가 문서에 얼마나 자주 등장하는지(TF), 그리고 해당 단어가 전체 문서 집합에서 얼마나 흔한지(IDF)를 고려하여 계산
- BM25 점수: TF-IDF를 개선한 알고리즘으로 각 단어의 중요성뿐만 아니라 문서의 길이도 고려
- 부스팅: 특정 필드에 대한 검색 결과를 더 중요하게 여기도록 부스팅 적용 가능
- bool 쿼리: 쿼리 내 must, should, filter, must_not 등의 절을 사용하여 검색 조건을 구조화할 수 있고 각 절을 각기 다른 방식으로 점수 계산에 영향을 줌
- script/function score: 사용자 정의 script나 function 사용하여 복잡한 랭킹 로직을 적용할 수 있으며 이를 통해 비즈니스 로직에 따라 문서의 랭킹 조정 가능
- 필드의 종류에 따라 다른 방식으로 점수 계산
- keyword 타입은 정확한 일치를 기준으로 점수 계산
2. score가 계산되는 순서
2.1 필터 로직
- 필터는 문서가 조건을 만족하는지 판별하는 역할
- 필터는 결과에 대한 점수를 계산하지 않으므로 쿼리보다 빠르게 실행하기 때문에 가능한 많은 필터를 사용하여 검색 범위를 좁히는 것을 권장
- 하지만 쿼리와 필터의 복잡성, 데이터의 분포, 샤드의 상태에 따라 실제 실행 순서는 달라질 수도 있음
2.2 비용이 낮은 쿼리/필터가 먼저 실행
- Elasticsearch는 cost() 메서드를 통해 각 쿼리와 필터의 비용을 추정하고 비용이 낮은 쿼리/필터부터 먼저 실행
2.3 post_filter
- 이름에서 유추할 수 있다시피 검색 결과가 반환되기 전 마지막으로 적용되는 필터
- 결과의 score에 영향을 주지 않으며 결과 집합을 추가로 필터링하는 데 사용
* 실제 실행 순서는 profile API를 통해 확인 가능
캐싱
- Elasticsearch에서 캐싱을 통해 검색 성능을 향상할 수 있음
1. 페이지 캐시
- OS가 파일 I/O의 성능 향상을 위해 사용하는 메모리 영역
- 한 번 읽은 파일의 내용을 페이지 캐시에 저장 후 다시 동일한 파일의 접근이 발생할 때 디스크에서 읽지 않고 페이지 캐시에서 빠르게 읽어올 수 있음
- Elasticsearch의 메모리 사용량을 시스템의 총메모리의 절반 이하로 유지하는 주요 이유 중 하나는 페이지 캐시를 효과적으로 사용하기 위해
- Elasticsearch를 설정할 때, JVM 힙 메모리(heap memory)의 크기를 시스템의 총 메모리의 절반 이하로 설정하는 것을 권장
- OS가 페이지 캐시로 사용할 수 있는 메모리를 충분히 확보하려면, Elasticsearch가 시스템 메모리의 절반 이하를 사용해야 함
- Elasticsearch가 과도하게 메모리를 사용하면, 운영 체제가 메모리 부족 상태에 빠질 수 있으며 이 경우 성능 저하나 시스템 불안정 유발할 수 있음
- JVM 힙 메모리가 너무 크면, GC가 더 자주 실행되거나 더 오래 걸릴 수 있음
- preload: 인덱스 설정을 통해 es 인덱스 데이터를 페이지 캐시에 미리 로딩되도록 Elasticsearch를 구성 가능
- Elasticsearch는 Lucene을 기반으로 하며, Lucene 인덱스 파일은 여러 세그먼트(segment)로 구성
- 각 세그먼트는 독립적인 파일 집합으로, 새로운 문서가 추가되거나 기존 문서가 삭제될 때마다 생성
- 프리로드는 이 세그먼트 파일을 미리 메모리에 로드하여 검색 성능을 최적화
- Elasticsearch에서 인덱스 프리로드는 주로 index.store.preload 설정을 통해 관리되며 해당 설정은 특정 파일 확장자를 지정하여 해당 파일들을 프리로드하도록 지시
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# nvd, dvd, tim, doc, dim 확장자를 가진 파일들을 프리로드 | |
PUT /my_index | |
{ | |
"settings": { | |
"index.store.preload": ["nvd", "dvd"] | |
} | |
} |
부연 설명
- nvd 파일은 필드 norms 데이터를 저장되며 norms는 문서 점수 계산에 사용되는 값으로, 특정 필드의 길이나 빈도 등을 정규화(normalization)한 값을 포함
- 이를 프리로드하면 문서 점수 계산 시 디스크 접근을 줄이고 성능을 향상할 수 있음
- dvd 파일은 도큐먼트 값(doc values)을 저장하며 도큐먼트 값은 필드 정렬, 집계(aggregation), 스크립팅 등에 사용되며, 주로 검색 시점이 아닌 인덱싱 시점에 생성
- 해당 데이터를 프리로드하면 이러한 작업들이 더 빠르게 수행될 수 있음
2. 샤드 레벨 캐시
- aggregation 동작에서 캐싱 발생
- aggregation 작업은 Elasticsearch에서 매우 자주 사용되는 기능으로, 데이터의 요약 정보를 제공하는 데 사용
- aggregation은 일반적으로 대규모 데이터를 처리하므로, 효율적인 캐싱 메커니즘이 필요
- ex) 날짜별 로그 집계를 하는 중 한 번은 2024-06-23 ~ 2024-06-28 구간을 집계하고 다음번에는 2024-06-16 ~ 2024-06-25 구간을 집계할 경우 기간이 겹치는 2024-06-23 ~ 2024-06-25 구간은 겹치기 때문에 해당 기간의 집계 정보가 캐시에 있을 경우 활용 가능
3. 노드 쿼리 캐시
- Elasticsearch 클러스터 내 각 노드에 존재하는 캐시로, 쿼리의 실행 결과를 저장하여 동일한 쿼리가 다시 실행될 때 캐시된 결과를 반환
- 서로 다른 쿼리 간 재사용되는 데이터를 캐시
- 쿼리 내 filter context(filter, must_not) 수행 시 동작
- 쿼리는 매번 달라지지만 필터는 동일할 경우 활용하기 좋음
- LRU(Least Recently Used) 방식으로 작동하여 가장 오랫동안 사용되지 않은 데이터를 캐시 교체 대상으로 지정
- 각 문서를 나타내는 배열, 특정 필터에 대한 전용 bitset을 만들어 특정 문서가 해당되면 1, 아니면 0으로 표시
- 기본적으로 캐시 개수는 10,000개를 가지며 힙 메모리의 10%까지만 캐시로 들고 있음
- 세그먼트 단위로 세그먼트 당 10,000개 이상의 문서를 가지고 해당 샤드의 전체 문서의 3% 이상을 차지하고 있어야 함
- 또한 한 번의 호출로 인해 캐시가 채워지지 않도록 캐싱에 적합한 최소 빈도에 대한 조건 존재
- 기본적으로는 5번 이상 호출 시 캐싱
- 비용이 상대적으로 비싼 쿼리는 두 번 이상 호출 시 캐싱
- indices.queries.cache.size(static) 통해 명시적으로 지정 가능
- API를 통해 클러스터별, 노드별, 그리고 인덱스별 캐시 확인 가능
- 클러스터별: GET _cluster/stats?filter_path=indices.query_cache API
- 노드별: GET /_nodes/stats/indices/query_cache?human API
- 인덱스별: GET {인덱스}/_stats?filter_path=indices.*.total_query_cache API
참고
- 패스트 캠퍼스 - 고성능 검색 엔진 구축으로 한 번에 끝내는 Elasticsearch
반응형
'Elastic Search' 카테고리의 다른 글
[Elasticsearch] 최적화를 위한 시스템 설정 (0) | 2024.07.13 |
---|---|
[Elasticsearch] 색인 (0) | 2024.06.28 |
[Elasticsearch] ILM (0) | 2024.06.27 |
[ELK] Beats 정리 (0) | 2024.06.25 |
[ELK] Logstash 정리 (0) | 2024.06.25 |