
이전에 했던 프로젝트에서 Elastic Search를 사용해서 전문 탐색 기능을 구현한 적이 있어서, 이력서에 적어뒀었다. 하지만 최근 본 면접에서
‘아 내가 Elastic Search에 대해서 진짜 아무것도 모르는구나..’
라는 생각을 하게되었고, 이번 기회에 한 번 찾아서 블로깅을 통해서 정리해볼 생각이다.
1. 소개
Elastic Search는 오픈 소스 기반의 분산형 검색 엔진으로, 텍스트, 숫자, 지리적 데이터, 구조화 및 비구조화 데이터를 빠르고 효율적으로 검색하고 분석할 수 있는 도구이다. Elastic Stack의 핵심 구성 요소 중 하나로, 대규모의 데이터를 실시간으로 처리하고 검색하는 데 최적화되어 있다. 특히, 대용량 데이터를 처리하면서도 검색 속도를 유지해야하는 시스템에서 많이 사용된다.
Elastic Search는 데이터를 인덱싱하여 구조화된 형태로 저장하고, 이를 통해 복잡한 검색과 분석 작업을 효율적으로 처리할 수 있다. 이러한 과정에 JSON형식의 문서로 데이터를 저장하며 RESTful API를 통해 데이터를 쉽게 검색하고 관리할 수 있는 점이 큰 장점이다.
Elastic Search의 주요 기능은 다음과 같다.
- Full-Text Search : 문서 내의 단어와 문장을 분석하여 관련성 높은 결과를 빠르게 찾아낸다.
- 실시간 데이터 처리 : 데이터가 추가되거나 변경됨에 따라 실시간으로 인덱스가 업데이트되고, 즉시 검색 결과에 반영된다.
- 확장성 : 수십억개의 문서와 페타바이트 단위의 데이터를 처리할 수 있으며, Sharding을 통해 여러 노드로 수평 확장할 수 있다.
- 분산형 아키텍처 : 데이터를 여러 서버에 분산 저장하여, 대규모 데이터 환경에서도 안정적인 성능을 유지한다.
이런 식의 큰 틀이 존재하지만 대표적인 사례로는 로그 분석, 추천 시스템, 제품 검색 엔진등이 있으며, 특히 IT 서비스 모니터링이나 데이터 분석에서 많이 활용된다.
2. Elastic Search의 기본 개념
Elastic Search는 데이터를 효율적으로 저장하고 검색하기 위해 여러 가지 핵심 개념을 제공한다. 이를 통해서 Elastic Search의 구조와 동작 방식을 잘 이해할 수 있었다.
2.1 Index와 Document
Elastic Search에서 Index는 데이터가 저장되는 논리적인 단위이다.
관계형 데이터베이스에서 Table에 해당하는 개념으로, 데이터를 저장하거나 검색할 때 인덱스를 기준으로 작업이 이루어진다. Index는 주제나 용도에 따라 여러 개를 생성할 수 있으며, 각 인덱스에는 여러 개의 Document의 위치가 포함된다.
Document는 JSON 형식으로 저장되는 데이터의 최소 단위이다. 예를 들면, 제품의 정보를 담은 인덱스에는 개별 제품에 대한 문서가 포함될 수 있으며, 이 문서에는 이름, 가격, 설명 등의 다양한 필드가 포함된다.
2.1.1 Index 생성 과정
Elastic Search를 단순하게 쓰기보다는 내부 구조에 대해서 잘 알고 있어야한다.
Elastic Search에서 데이터를 빠르고 효율적으로 찾기 위한 원리는 Index 생성과 Inverted-Index 구조에 기반하고 있다.
Elastic Search의 Index 생성 과정은 3단계를 통해서 생성된다.
1. Index 생성 요청
PUT /my_index
{
"settings": {
"number_of_shards": 3, # 기본적으로 3개의 샤드로 인덱스를 분할
"number_of_replicas": 1 # 각 샤드에 대해 1개의 복제본을 생성
}
}
기존의 RESTful API를 사용해본 경험이 있다면, 데이터 베이스에 어떤 상태를 추가 또는 등록하는 경우에는 POST 메서드를 사용할 것이다.
Elastic Search에서는 POST 대신 PUT 메서드를 사용해서 인덱스를 생성하게 된다. POST 메서드는 어떤 인덱스에 문서를 추가할 때 사용하게 된다.
Index를 생성할 때는 Index의 이름과 함께 설정 정보(Shard 수, Replica 수)를 명시할 수 있다. 이 과정에서 인덱스는 여러 Shard에 나뉘어 물리적으로 저장되며, 각 샤드에는 데이터를 저장하는 단위인 Document가 저장된다.
2. Mapping 설정
인덱스를 생성할 때는 각 문서의 Mapping을 설정할 수 있다. Mapping은 각 필드의 데이터 타입을 정의하는 역할을 한다. 쉽게 생각해서 스키마라고 생각하면 된다. 예를 들어, 텍스트 필드, 숫자 필드, 날짜 필드 등의 데이터 타입을 지정할 수 있다.
만약 Mapping을 사전에 정의하지 않으면, Elastic Search는 자동으로 데이터를 분석하여 적절한 데이터 타입을 추론해 적용한다.
PUT /my_index/_mapping
{
"properties": {
"name": { "type": "text" },
"price": { "type": "double" },
"description" : { "type": "text" },
"created_at": { "type": "date" }
}
}
3. Document 추가
인덱스가 생성된 후에는 데이터를 문서 형태로 인덱스에 저장할 수 있다. Elastic Search는 데이터를 JSON 형식으로 저장하며, 각 문서에는 고유한 ID가 부여된다.
POST /my_index/_doc/1
{
"name": "Product A",
"price": 299.99,
"description": "High-quality product",
"created_at": "2024-10-23T10:15:30"
}
1과 같은 방식으로 사용자가 직접 ID값을 부여할 수도 있고, 명시하지 않는 경우는 자동으로 고유한 ID값을 부여한다. 이와 같은 방식으로 문서를 저장하면 Elastic Search는 문서의 각 필드를 분석하고 이를 검색 가능하도록 Indexing한다.
2.1.2 데이터를 빠르게 찾는 원리
Elastic Search는 데이터를 빠르게 검색하기 위해 역 인덱스(Inverted Index)라는 데이터 구조를 사용한다. 이 구조는 텍스트 검색 엔진에서 자주 사용되는 방식으로, 각 단어가 어느 문서에 포함되어 있는지를 빠르게 찾을 수 있게 합니다.
1. 역 인덱스(Inverted Index)
관계형 데이터베이스에서의 인덱스는 특정 컬럼의 값을 기준으로 데이터를 정렬하여 빠르게 찾는 방식입니다. 하지만 Elastic Search는 문서 내의 모든 단어를 각각의 Token으로 변환하고, 해당 토큰들이 포함된 문서를 Indexing한다. 즉, 단어와 문서 간의 매핑을 미리 생성해두는 방식이다.
예를 들어, “A sample product”라는 텍스트가 포함된 문서를 Indexing하면 다음과 같은 역 인덱스가 만들어집니다
"A" → [문서 1]
"sample" → [문서 1]
"product" → [문서 1]
이를 통해 특정 단어를 검색할 때, 해당 단어가 포함된 문서를 즉시 찾아낼 수 있습니다.
2. 분석기(Analyzer)
Elastic Search는 문서를 저장할 때 Analyzer를 사용하여 텍스트를 처리합니다. 분석기는 문서를 저장할 때 텍스트를 토큰화하고, Stopword나 대소문자 구분 등 다양한 규칙을 적용하여 인덱스를 최적화한다. 이를 통해 불필요한 정보는 배제하고 검색 효율을 높일 수 있다. 이 부분이 사실상 Elastic Search를 잘 사용하기 위해서 제일 중요한 부분이라고 생각한다.
3. 쿼리 처리: 사용자가 검색 쿼리를 보낼 때, Elastic Search는 사용된 단어를 토큰화하고, 미리 생성된 역 인덱스를 통해 해당 단어가 포함된 문서를 빠르게 찾아낸다. 이 과정에서 순위 기반 검색(relevance scoring)을 통해 검색 결과의 우선순위를 정리하여, 가장 관련성이 높은 문서를 먼저 반환한다.
4. 분산 구조: Elastic Search는 데이터를 여러 개의 Shard에 분산 저장하고, 각 샤드에서 병렬적으로 검색을 수행한다. 이를 통해 대량의 데이터를 매우 짧은 시간 안에 검색할 수 있다. 또한 Replica 샤드가 존재하여, 읽기 작업을 복제본에서 분산 처리할 수 있어 성능이 더욱 향상된다.
결과적으로, Elastic Search는 인덱스를 생성하고 역 인덱스 구조를 활용함으로써 대규모 데이터 속에서도 매우 빠르고 효율적으로 검색을 수행할 수 있습니다.
2.2 Shard와 Replica
Elastic Search는 데이터를 Shard로 분할하여 저장한다. Shard는 물리적인 데이터 저장 단위로, 하나의 인덱스를 여러 샤드로 나누어 저장함으로써 대규모 데이터를 효과적으로 처리할 수 있다. 예를 들어, 대규모 데이터를 다루는 경우 단일 노드에서 처리하기 어려울 수 있기 때문에, 여러 노드에 샤드를 분산 배치하여 성능을 최적화한다.
샤드는 2가지 유형으로 나뉜다.
- 기본 샤드 (Primary Shard) : 데이터의 기본 저장소 역할을 하며, 각 인덱스에는 최소 하나 이상의 기본 샤드가 존재한다.
- 복제본 (Replica) : 기본 샤드의 복사본으로, 장애가 발생할 경우, 데이터를 안전하게 보존하고, 읽기 성능을 향상시키기 위한 용도로 사용한다. Elastic Search는 기본적으로 각 샤드에 대해 하나 이상의 본제본을 유지할 수있다.
2.3 Mapping과 데이터 삽입
Elastic Search에서 Mapping은 문서 내 각 필드의 구조와 데이터 타입을 정의하는 설정이다. 관계형 데이터베이스에서 스키마에 해당하는 개념으로, 매핑을 통해 어떤 필드가 문자열, 숫자, 날짜 등의 타입인지 명시할 수 있다.
Elastic Search는 다양한 데이터 타입을 지원한다.
- String: 텍스트 데이터로, 분석하여 검색에 사용할 수 있다.
- Number: 정수, 부동 소수점 등 다양한 숫자 타입을 지원한다.
- Date: 시간 정보가 포함된 데이터로, 다양한 포맷을 지원다.
- Geo Point: 위도와 경도를 저장하여 위치 기반 검색에 사용된다.
Elastic Search는 기본적으로 Mapping을 자동으로 생성하지만, 필요한 경우 명시적으로 Mapping을 정의하여 검색 성능을 향상시키거나 필드 분석 방식을 제어할 수 있다.
이외에도 다양한 타입을 지원하며, 특정 객체 내부에 다른 객체가 들어가는 경우, Nested를 사용하여 내부 객체를 타입을 Mapping 할 수 있다.
public class ProjectDocuments implements DistributedLockInterface {
@Id
@Field(name = "id", type = FieldType.Keyword)
private Long id;
@Field(name = "title", type = FieldType.Text)
private String title;
@Field(name = "subject", type = FieldType.Text)
private String subject;
@Field(name = "feature", type = FieldType.Text)
private String feature;
......
@Field(name = "comments", type = FieldType.Nested)
private List<Comment> comments;
......
이런 방식으로 특정 Document 내부에 Nested를 활용하여 데이터 타입을 지정할 수 있다.
3. Elastic Search 최적화
Elastic Search는 대용량 데이터에 대한 검색과 분석을 빠르게 처리할 수 있도록 설계된 시스템이지만, 잘못된 설정이나 인덱스 설계로 인해 성능이 저하될 수 있다. 최적화를 통해 성능을 향상시키고 안정성을 보장할 수 있다.
3.1 인덱스 설계 최적화
Elastic Search의 성능을 최적화하려면 먼저 인덱스 설계를 신중하게 해야 한다. 데이터 구조와 인덱싱 전략은 검색 성능과 자원 사용에 큰 영향을 미친다.
1. 올바른 샤드 크기 설정
Elastic Search는 데이터를 Shard로 분할하여 저장한다. 너무 많은 샤드를 생성하거나 샤드 크기가 너무 크면 성능에 문제가 발생할 수 있다. 적절한 샤드 크기를 설정하는 것이 매우 중요하다.
- 샤드 수 최적화: 샤드가 너무 많으면 오버헤드가 발생하고, 너무 적으면 데이터 분산 효과가 떨어진다. 일반적으로 샤드당 약 10GB~50GB 정도의 데이터를 저장하는 것이 권장된다. 노드 수와 데이터 양에 따라 적절한 샤드 크기와 수를 설정해야 한다.
- 복제본 수 조정: 복제본(Replica)은 데이터 안정성과 읽기 성능을 향상시키는 역할을 한다. 복제본이 많을수록 읽기 성능은 높아지지만, 그만큼 리소스가 많이 소모되므로 복제본 수를 환경에 맞게 조정해야 한다.
2. 매핑 최적화 (필드 타입 설정)
Elastic Search는 문서의 Mapping을 통해 각 필드의 데이터 타입을 지정한다. 잘못된 매핑은 검색 성능을 저하시킬 수 있으므로, 올바른 필드 타입을 정의하는 것이 중요하다.
- 필드 데이터 타입 최소화: 텍스트 분석이 필요하지 않은 필드는 keyword 타입으로 설정하여 인덱스 크기를 줄이고 성능을 최적화할 수 있다. 예를 들어, 제품의 이름이나 설명과 같은 필드에는 text 타입을 사용하지만, 카테고리나 상태와 같이 정확히 일치하는 필드에는 keyword 타입을 사용하는 것이 좋다.
- 필드의 분석기 설정: Analyzer는 텍스트를 분해하여 검색할 수 있는 형태로 변환하는 역할을 한다. 기본 분석기 외에 사용자가 직접 커스텀 분석기를 설정하여 불필요한 분석 작업을 줄이면 성능을 최적화할 수 있다. 예를 들어, Stopwords를 제거하거나, 검색 요구에 맞는 분석기(예: 소문자 변환, Stemming 적용 등)를 적용할 수 있다.
3. 동적 매핑 비활성화
Elastic Search는 기본적으로 새로운 필드를 동적으로 추가할 때 자동으로 매핑을 생성한다. 그러나 너무 많은 필드가 동적으로 추가되면 성능에 부정적인 영향을 미칠 수 있다. **동적 매핑(dynamic mapping)**을 비활성화하거나 제한하여 불필요한 필드 생성을 방지할 수 있다.
index.mapper.dynamic: false
3.2 쿼리 최적화
Elastic Search의 쿼리는 매우 강력하지만, 비효율적으로 작성된 쿼리는 성능 저하를 초래할 수 있다. 쿼리 성능을 최적화하기 위한 몇 가지 방법이 있다.
1. 필터 사용
쿼리에서 Filter를 사용하는 것은 성능을 향상시키는 중요한 방법이다. 필터는 쿼리와 달리 관련성 점수를 계산하지 않으며, 캐싱을 통해 성능을 최적화할 수 있다.
- 정확한 매칭에는 필터 사용: 날짜, 숫자, boolean 값처럼 정확한 매칭이 필요한 경우에는 쿼리 대신 필터를 사용하는 것이 좋다. 예를 들어, 특정 범위의 날짜나 정확한 값에 대한 검색은 필터를 사용하여 쿼리 처리 시간을 줄일 수 있다.
{
"query": {
"bool": {
"filter": {
"term": {
"status": "active"
}
}
}
}
}
2. 필요한 필드만 검색
Elastic Search는 기본적으로 문서의 모든 필드를 반환하지만, 필요 없는 필드를 제외하면 성능을 개선할 수 있다. 특히, 큰 문서에서 모든 데이터를 반환할 필요가 없다면 source 필드 제어를 통해 필요한 데이터만 반환하도록 할 수 있다.
{
"_source": ["name", "price"],
"query": {
"match": {
"description": "search term"
}
}
}
3. 비싼 쿼리 피하기
wildcard, regexp 등의 쿼리는 성능에 큰 영향을 미친다. 특히 대량의 데이터를 검색하는 경우, 이와 같은 비싼 쿼리는 전체 성능에 악영향을 줄 수 있다. 대신 정확한 검색이 필요한 경우 keyword 필드에 대해 정확히 일치하는 검색을 사용하고, 복잡한 정규 표현식이나 와일드카드 사용은 가급적 피해야 한다.
4. 애그리게이션 최적화
애그리게이션은 데이터를 집계하고 요약하는 데 강력한 기능을 제공하지만, 잘못 사용하면 성능 문제가 발생할 수 있다.
- 집계 범위 제한: 애그리게이션을 사용할 때 너무 많은 데이터 범위에서 집계를 수행하면 리소스가 많이 소모된다. 필요하지 않은 데이터는 필터로 제외하고 집계 범위를 적절히 제한하는 것이 좋다
- Cardinality 집계 최소화: Cardinality 애그리게이션(고유값 계산)은 비용이 많이 드는 연산이다. 가능하면 이 집계는 최소한으로 사용하고, 필요한 경우 데이터 모델을 재구성하는 방법을 고려해야 한다.
3.3 캐싱 및 메모리 관리
Elastic Search는 자동으로 캐싱을 사용하여 자주 실행되는 쿼리의 성능을 향상시킨다. 적절한 캐싱 전략을 통해 메모리 사용을 최적화할 수 있다.
1. 필터 캐싱
쿼리에서 필터를 사용할 경우, 필터의 결과는 기본적으로 캐시된다. 캐시는 재사용되므로 동일한 필터 쿼리를 여러 번 실행할 때 성능이 크게 향상된다.
- 필터 쿼리는 성능을 높이기 위해 캐싱을 사용하지만, 너무 자주 변경되는 데이터에는 캐시를 사용하지 않는 것이 좋다. 예를 들어, 자주 업데이트되는 값에는 캐시를 적용하지 않는 것이 성능에 유리하다.
2. JVM 힙 메모리 설정
Elastic Search는 JVM 기반이므로 힙 메모리 설정이 매우 중요하다. JVM 힙 메모리 크기를 잘못 설정하면 **GC(Garbage Collection)**로 인해 성능 저하가 발생할 수 있다.
- 적절한 힙 메모리 크기 설정: 힙 메모리는 너무 크거나 작으면 문제가 발생할 수 있다. 일반적으로 전체 시스템 메모리의 절반을 할당하되, 최대 32GB 이하로 설정하는 것이 좋다. 32GB를 초과하면 JVM이 힙 메모리를 효율적으로 관리하지 못할 수 있다.
- GC 튜닝: Elastic Search는 기본적으로 JVM의 가비지 컬렉터를 사용하지만, 대용량 데이터를 처리할 경우 GC 튜닝이 필요할 수 있다. GC 로그를 분석하고 적절한 설정을 통해 GC로 인한 성능 저하를 최소화해야 한다.
3. 메모리 활용 극대화
Elastic Search는 검색 성능을 높이기 위해 파일 시스템 캐시를 적극적으로 사용한다. 따라서 시스템의 물리적 메모리(RAM)를 최대한 확보하고, 인덱스 데이터를 파일 시스템 캐시에 로드하여 빠른 검색이 가능하도록 해야 한다.
- RAM 활용: 가능한 한 많은 데이터를 메모리에 캐시하여 디스크 I/O를 최소화할 수 있도록 시스템의 RAM 용량을 확장하는 것이 좋다.
3.4 인덱스 관리 전략
Elastic Search의 성능을 유지하려면 인덱스를 효율적으로 관리해야 한다. 오래된 데이터는 주기적으로 삭제하거나 보관 정책을 적용하여 리소스를 절약할 수 있다.
1. 인덱스 롤오버(Rollover)
데이터가 지속적으로 추가되는 로그 데이터와 같은 경우, 하나의 인덱스가 너무 커지면 성능이 저하될 수 있다. Elastic Search의 롤오버 인덱스(Rollover Index) 기능을 사용한다. Elastic Search의 롤오버 인덱스 기능은 일정 조건에 도달하면 새로운 인덱스를 생성하고 데이터를 그곳으로 저장할 수 있도록 한다. 이 방법을 사용하면 대용량의 데이터를 효율적으로 관리할 수 있으며, 인덱스의 크기가 너무 커져 성능 저하가 발생하는 것을 방지할 수 있다.
예를 들어, 인덱스 크기가 50GB에 도달하면 새로운 인덱스로 자동 롤오버를 수행하도록 설정할 수 있다. 이 방법은 특히 로그 데이터와 같은 연속적으로 증가하는 데이터를 처리할 때 유용하다.
POST /my_index/_rollover
{
"conditions": {
"max_age": "7d", // 7일 경과 시 롤오버
"max_size": "50gb" // 50GB를 초과할 시 롤오버
}
}
2. 데이터 보존 정책 (Index Lifecycle Management, ILM)
Elastic Search는 Index Lifecycle Management (ILM) 기능을 통해 오래된 데이터를 자동으로 관리할 수 있다. 이 기능을 사용하면 데이터의 수명 주기를 정의하고, 그에 따라 인덱스를 삭제하거나 보관하는 등의 작업을 자동화할 수 있다. ILM은 일반적으로 로그 데이터나 시간 기반 데이터를 관리할 때 사용된다.
ILM 정책은 크게 네 가지 단계로 구성된다:
- Hot Phase: 데이터를 적극적으로 인덱싱하고 검색하는 단계이다.
- Warm Phase: 덜 자주 검색되는 데이터를 읽기 전용 인덱스로 전환하여 리소스를 절약한다.
- Cold Phase: 오래된 데이터를 저비용 스토리지로 옮기며, 검색 빈도가 낮은 데이터를 효율적으로 관리한다.
- Delete Phase: 데이터가 더 이상 필요하지 않을 경우 인덱스를 자동으로 삭제한다.
PUT _ilm/policy/my_policy
{
"policy": {
"phases": {
"hot": {
"actions": {
"rollover": {
"max_size": "50GB",
"max_age": "30d"
}
}
},
"delete": {
"min_age": "90d",
"actions": {
"delete": {}
}
}
}
}
}
이와 같은 방식으로 ILM을 설정하면, 데이터를 단계별로 관리하고 오래된 인덱스는 자동으로 삭제하여 스토리지를 최적화할 수 있다.
3. 읽기 전용 인덱스
데이터가 변경되지 않는 경우, 인덱스를 읽기 전용(read-only) 상태로 전환하여 성능을 향상시킬 수 있다. 읽기 전용 인덱스는 더 이상 인덱싱 작업이 발생하지 않으므로 리소스 소모가 줄어들고, 검색 성능을 극대화할 수 있다.
PUT /my_index/_settings
{
"index.blocks.write": true
}
이 설정을 통해 인덱스를 읽기 전용으로 전환하고, 불필요한 쓰기 작업을 방지할 수 있다.
3.5 성능 모니터링 및 분석
Elastic Search 클러스터의 상태와 성능을 지속적으로 모니터링하고 분석하는 것은 최적화의 중요한 부분이다. 이를 통해 문제를 사전에 감지하고 성능 저하를 방지할 수 있다.
1. 클러스터 상태 모니터링
Elastic Search는 클러스터의 상태를 모니터링할 수 있는 다양한 API를 제공한다. /_cluster/health API를 사용하여 클러스터, 노드, 샤드의 상태를 실시간으로 확인할 수 있다.
GET /_cluster/health
이 API는 클러스터의 상태(green, yellow, red)를 반환하며, 클러스터가 원활하게 작동하고 있는지 여부를 확인하는 데 사용된다.
2. 노드 및 샤드 상태 모니터링
Elastic Search는 각 노드와 샤드의 성능 지표를 실시간으로 모니터링할 수 있는 API를 제공한다. 이를 통해 리소스 사용 현황을 확인하고, 특정 노드가 과부하 상태에 있는지, 샤드가 불균형하게 분배되었는지 등을 파악할 수 있다.
- 노드 상태 확인: /nodes/stats API를 사용하여 각 노드의 CPU, 메모리, 디스크 사용량을 확인할 수 있다.
GET /_nodes/stats
- 샤드 재할당: 특정 노드에 샤드가 과도하게 할당된 경우, 클러스터의 리밸런싱 작업을 통해 샤드를 재분배하여 부하를 분산할 수 있다.
3. Kibana를 통한 시각화
Elastic Search의 성능을 시각적으로 모니터링하기 위해 Kibana와 같은 도구를 사용할 수 있다. Kibana는 Elastic Search와 통합되어 클러스터의 상태, 인덱스 사용량, 쿼리 성능 등을 직관적으로 시각화해준다.
- Elastic Stack Monitoring: Elastic Search 클러스터의 모든 성능 지표를 모니터링할 수 있으며, CPU 사용량, 메모리 상태, 쿼리 응답 시간 등을 대시보드로 확인할 수 있다.
4. Elastic Search의 한계 및 대안
Elastic Search는 매우 강력하고 확장성이 뛰어난 검색 및 분석 도구이지만, 특정 시나리오에서는 한계점이 존재할 수 있다. 이러한 한계를 이해하고 적절한 해결 방법을 찾거나, 상황에 따라 Elastic Search의 대안을 고려하는 것이 필요하다. 이 섹션에서는 Elastic Search의 주요 한계점과 해결 방법, 그리고 Elastic Search의 대안으로 사용할 수 있는 Solr와 OpenSearch를 비교하여 설명한다.
4.1 Elastic Search의 한계점과 해결 방법
Elastic Search는 다양한 기능을 제공하지만, 몇 가지 주요 한계점이 있다. 이 한계점들을 적절히 해결하지 않으면 성능 저하나 안정성 문제를 겪을 수 있다.
1. 대규모 데이터 관리의 복잡성
Elastic Search는 데이터를 샤드로 분산 저장하므로, 데이터 양이 많아질수록 샤드 및 인덱스 관리를 신중하게 해야 한다. 특히 대규모 데이터를 다루는 경우 샤드의 크기와 복제본 수 등을 잘못 설정하면 성능이 급격히 저하될 수 있다.
- 해결 방법: 샤드 수와 크기를 적절하게 조정하는 것이 중요하다. 인덱스의 크기를 일정하게 유지하기 위해 롤오버 인덱스나 ILM(인덱스 수명 관리) 기능을 사용하여 오래된 데이터를 관리하고, 필요 없는 인덱스를 삭제하거나 보관 정책을 통해 데이터 관리를 자동화할 수 있다.
2. 복잡한 쿼리 성능 저하
Elastic Search는 매우 유연한 쿼리 언어(DSL)를 제공하지만, 복잡한 애그리게이션이나 많은 필드를 포함한 쿼리는 성능에 부정적인 영향을 미칠 수 있다. 특히 정규 표현식, 와일드카드, 고유값 계산 등은 성능이 저하될 수 있는 고비용 연산이다.
- 해결 방법: 복잡한 쿼리를 최적화하기 위해, 필터 기반의 단순한 쿼리로 변환하거나, 필요한 필드만을 검색하여 리소스 사용을 줄일 수 있다. 또한, 쿼리 성능이 낮은 경우 쿼리 프로파일링을 통해 문제의 쿼리를 분석하고 최적화해야 한다.
3. 장기적인 클러스터 관리
Elastic Search 클러스터는 노드가 많아지면서 관리가 점점 복잡해질 수 있다. 특히 장애가 발생할 경우 복구 작업이나 샤드 재배치가 수동으로 이루어질 때 복잡한 설정이 필요할 수 있다.
- 해결 방법: 자동화된 클러스터 관리 도구를 사용하거나, 클라우드 기반의 Elastic Cloud 서비스를 통해 클러스터 관리의 부담을 줄일 수 있다. 또한, 클러스터 모니터링 도구(Kibana나 X-Pack 모니터링)를 활용하여 장애가 발생하기 전에 성능 문제를 예측하고 대응할 수 있다.
4. 고비용 하드웨어 요구
Elastic Search는 대규모 데이터를 빠르게 검색하고 분석하기 위해 많은 메모리와 CPU 자원을 요구한다. 따라서 고성능의 하드웨어가 필요한 경우 운영 비용이 증가할 수 있다.
- 해결 방법: 성능에 영향을 주는 필드 데이터나 애그리게이션 작업을 최소화하고, 쿼리 캐싱을 적극적으로 활용하여 자원 사용을 줄이는 방법을 사용할 수 있다. 또한, 효율적인 인덱스 설계 및 메모리 설정을 통해 리소스 활용도를 최대화할 수 있다.
5. 보안 및 인증 관리
Elastic Search의 기본 설정에서는 보안이 활성화되어 있지 않다. 즉, 외부에서 접근 가능한 환경에서는 보안 문제가 발생할 수 있다. 기본적으로 인증, 접근 제어, 데이터 암호화 기능이 추가 설정 없이 제공되지 않는다.
- 해결 방법: X-Pack이나 Elastic Stack의 보안 모듈을 사용하여 TLS/SSL 암호화, 사용자 인증, 역할 기반 접근 제어(RBAC) 기능을 활성화해야 한다. 이로써 데이터 보안을 강화하고 민감한 정보의 접근을 제한할 수 있다.
하지만, X-Pack을 사용하려면 유료 버전의 Elastic Search를 사용해야한다는 점이 단점으로 꼽힌다. 혼자거나 소규모 프로젝트에서는 상관없지만, 회사입장에서는 보안적인 측면도 고려해야 하기때문에, Elastic Search보다는 다른 대안이 필요하다.
4.2 Elastic Search의 대안 비교
그렇다면, Elastic Search를 대체할 수 있는 도구들은 어떤 도구들이 있을까?
물론 Elastic Search는 강력한 검색 엔진이지만, 특정 시나리오에서는 다른 검색 엔진을 고려할 필요가 있다. 특히 Solr와 OpenSearch는 Elastic Search의 대안으로 자주 언급되는 도구들이다. 각 도구는 고유한 장점과 특징이 있으며, 상황에 따라 더 적합한 선택이 될 수 있다.
1. Apache Solr
Apache Solr는 Elastic Search와 함께 대표적인 오픈 소스 검색 엔진 중 하나이다. Solr는 Apache Lucene 기반으로 개발되었으며, 다수의 기업에서 대규모 검색 시스템을 위해 사용하고 있다. Solr는 특히 정교한 텍스트 검색 및 맞춤형 기능을 제공하는 데 강점을 가진다.
주요 특징
- 고급 텍스트 분석 기능: Solr는 매우 강력한 텍스트 분석 기능을 제공하며, 복잡한 텍스트 처리 및 검색에 강점을 가진다.
- 완성도 높은 UI 관리 툴: Solr는 기본적으로 제공하는 관리자 콘솔이 사용하기 직관적이며 강력한 설정 기능을 제공한다.
- 정교한 데이터 캐싱: Solr는 캐싱 기능이 매우 뛰어나며, 복잡한 쿼리에도 빠른 응답을 제공할 수 있다.
- XML 및 JSON 지원: Solr는 XML 포맷을 기본으로 지원하며, Elastic Search와는 달리 데이터 전송에 있어 XML과 JSON을 모두 사용할 수 있다.
단점
- 분산 처리에 있어 Elastic Search에 비해 상대적으로 복잡하다.
- 확장성과 사용자 편의성이 Elastic Search에 비해 낮다는 평가를 받는다.
2. OpenSearch
OpenSearch는 Elastic Search의 포크(fork) 버전으로, Amazon Web Services(AWS)에서 주도적으로 개발하는 오픈 소스 프로젝트이다. Elastic Search의 라이선스 변경 이후, 자유로운 오픈 소스 사용을 위해 OpenSearch가 탄생하였다. 사실상 동일하다
주요 특징:
- Elastic Search와 높은 호환성: OpenSearch는 Elastic Search 7.10 버전 이후로 포크된 프로젝트이기 때문에, 기존 Elastic Search 사용자에게 익숙한 기능과 인터페이스를 제공한다.
- 완전한 오픈 소스: OpenSearch는 Apache 2.0 라이선스를 따르기 때문에 상업적 사용에 제한이 없다.
- AWS 통합: OpenSearch는 AWS 환경에서 매우 높은 호환성을 제공하며, 특히 Amazon의 관리형 서비스(OpenSearch Service)를 통해 손쉽게 클러스터를 관리할 수 있다.
- 보안 및 모니터링: OpenSearch는 기본적으로 보안, 인증, 모니터링 기능이 포함되어 있어 추가적인 설치나 라이선스가 필요하지 않다.
단점:
- Elastic Search와 완전히 동일하지 않으며, 향후 Elastic Search와의 기능 차이가 더 벌어질 가능성이 있다.
- 커뮤니티와 에코시스템이 Elastic Search에 비해 상대적으로 작다.

[Medium Blog]
[Elasticsearch] Elasticsearch란?
Elasticsearch에 대해서 알아보자.
medium.com
'공부' 카테고리의 다른 글
[Kafka] Kafka Admin과 Admin Client (0) | 2024.11.22 |
---|---|
정규 표현식 Regular Expression (0) | 2024.06.23 |

이전에 했던 프로젝트에서 Elastic Search를 사용해서 전문 탐색 기능을 구현한 적이 있어서, 이력서에 적어뒀었다. 하지만 최근 본 면접에서
‘아 내가 Elastic Search에 대해서 진짜 아무것도 모르는구나..’
라는 생각을 하게되었고, 이번 기회에 한 번 찾아서 블로깅을 통해서 정리해볼 생각이다.
1. 소개
Elastic Search는 오픈 소스 기반의 분산형 검색 엔진으로, 텍스트, 숫자, 지리적 데이터, 구조화 및 비구조화 데이터를 빠르고 효율적으로 검색하고 분석할 수 있는 도구이다. Elastic Stack의 핵심 구성 요소 중 하나로, 대규모의 데이터를 실시간으로 처리하고 검색하는 데 최적화되어 있다. 특히, 대용량 데이터를 처리하면서도 검색 속도를 유지해야하는 시스템에서 많이 사용된다.
Elastic Search는 데이터를 인덱싱하여 구조화된 형태로 저장하고, 이를 통해 복잡한 검색과 분석 작업을 효율적으로 처리할 수 있다. 이러한 과정에 JSON형식의 문서로 데이터를 저장하며 RESTful API를 통해 데이터를 쉽게 검색하고 관리할 수 있는 점이 큰 장점이다.
Elastic Search의 주요 기능은 다음과 같다.
- Full-Text Search : 문서 내의 단어와 문장을 분석하여 관련성 높은 결과를 빠르게 찾아낸다.
- 실시간 데이터 처리 : 데이터가 추가되거나 변경됨에 따라 실시간으로 인덱스가 업데이트되고, 즉시 검색 결과에 반영된다.
- 확장성 : 수십억개의 문서와 페타바이트 단위의 데이터를 처리할 수 있으며, Sharding을 통해 여러 노드로 수평 확장할 수 있다.
- 분산형 아키텍처 : 데이터를 여러 서버에 분산 저장하여, 대규모 데이터 환경에서도 안정적인 성능을 유지한다.
이런 식의 큰 틀이 존재하지만 대표적인 사례로는 로그 분석, 추천 시스템, 제품 검색 엔진등이 있으며, 특히 IT 서비스 모니터링이나 데이터 분석에서 많이 활용된다.
2. Elastic Search의 기본 개념
Elastic Search는 데이터를 효율적으로 저장하고 검색하기 위해 여러 가지 핵심 개념을 제공한다. 이를 통해서 Elastic Search의 구조와 동작 방식을 잘 이해할 수 있었다.
2.1 Index와 Document
Elastic Search에서 Index는 데이터가 저장되는 논리적인 단위이다.
관계형 데이터베이스에서 Table에 해당하는 개념으로, 데이터를 저장하거나 검색할 때 인덱스를 기준으로 작업이 이루어진다. Index는 주제나 용도에 따라 여러 개를 생성할 수 있으며, 각 인덱스에는 여러 개의 Document의 위치가 포함된다.
Document는 JSON 형식으로 저장되는 데이터의 최소 단위이다. 예를 들면, 제품의 정보를 담은 인덱스에는 개별 제품에 대한 문서가 포함될 수 있으며, 이 문서에는 이름, 가격, 설명 등의 다양한 필드가 포함된다.
2.1.1 Index 생성 과정
Elastic Search를 단순하게 쓰기보다는 내부 구조에 대해서 잘 알고 있어야한다.
Elastic Search에서 데이터를 빠르고 효율적으로 찾기 위한 원리는 Index 생성과 Inverted-Index 구조에 기반하고 있다.
Elastic Search의 Index 생성 과정은 3단계를 통해서 생성된다.
1. Index 생성 요청
PUT /my_index
{
"settings": {
"number_of_shards": 3, # 기본적으로 3개의 샤드로 인덱스를 분할
"number_of_replicas": 1 # 각 샤드에 대해 1개의 복제본을 생성
}
}
기존의 RESTful API를 사용해본 경험이 있다면, 데이터 베이스에 어떤 상태를 추가 또는 등록하는 경우에는 POST 메서드를 사용할 것이다.
Elastic Search에서는 POST 대신 PUT 메서드를 사용해서 인덱스를 생성하게 된다. POST 메서드는 어떤 인덱스에 문서를 추가할 때 사용하게 된다.
Index를 생성할 때는 Index의 이름과 함께 설정 정보(Shard 수, Replica 수)를 명시할 수 있다. 이 과정에서 인덱스는 여러 Shard에 나뉘어 물리적으로 저장되며, 각 샤드에는 데이터를 저장하는 단위인 Document가 저장된다.
2. Mapping 설정
인덱스를 생성할 때는 각 문서의 Mapping을 설정할 수 있다. Mapping은 각 필드의 데이터 타입을 정의하는 역할을 한다. 쉽게 생각해서 스키마라고 생각하면 된다. 예를 들어, 텍스트 필드, 숫자 필드, 날짜 필드 등의 데이터 타입을 지정할 수 있다.
만약 Mapping을 사전에 정의하지 않으면, Elastic Search는 자동으로 데이터를 분석하여 적절한 데이터 타입을 추론해 적용한다.
PUT /my_index/_mapping
{
"properties": {
"name": { "type": "text" },
"price": { "type": "double" },
"description" : { "type": "text" },
"created_at": { "type": "date" }
}
}
3. Document 추가
인덱스가 생성된 후에는 데이터를 문서 형태로 인덱스에 저장할 수 있다. Elastic Search는 데이터를 JSON 형식으로 저장하며, 각 문서에는 고유한 ID가 부여된다.
POST /my_index/_doc/1
{
"name": "Product A",
"price": 299.99,
"description": "High-quality product",
"created_at": "2024-10-23T10:15:30"
}
1과 같은 방식으로 사용자가 직접 ID값을 부여할 수도 있고, 명시하지 않는 경우는 자동으로 고유한 ID값을 부여한다. 이와 같은 방식으로 문서를 저장하면 Elastic Search는 문서의 각 필드를 분석하고 이를 검색 가능하도록 Indexing한다.
2.1.2 데이터를 빠르게 찾는 원리
Elastic Search는 데이터를 빠르게 검색하기 위해 역 인덱스(Inverted Index)라는 데이터 구조를 사용한다. 이 구조는 텍스트 검색 엔진에서 자주 사용되는 방식으로, 각 단어가 어느 문서에 포함되어 있는지를 빠르게 찾을 수 있게 합니다.
1. 역 인덱스(Inverted Index)
관계형 데이터베이스에서의 인덱스는 특정 컬럼의 값을 기준으로 데이터를 정렬하여 빠르게 찾는 방식입니다. 하지만 Elastic Search는 문서 내의 모든 단어를 각각의 Token으로 변환하고, 해당 토큰들이 포함된 문서를 Indexing한다. 즉, 단어와 문서 간의 매핑을 미리 생성해두는 방식이다.
예를 들어, “A sample product”라는 텍스트가 포함된 문서를 Indexing하면 다음과 같은 역 인덱스가 만들어집니다
"A" → [문서 1]
"sample" → [문서 1]
"product" → [문서 1]
이를 통해 특정 단어를 검색할 때, 해당 단어가 포함된 문서를 즉시 찾아낼 수 있습니다.
2. 분석기(Analyzer)
Elastic Search는 문서를 저장할 때 Analyzer를 사용하여 텍스트를 처리합니다. 분석기는 문서를 저장할 때 텍스트를 토큰화하고, Stopword나 대소문자 구분 등 다양한 규칙을 적용하여 인덱스를 최적화한다. 이를 통해 불필요한 정보는 배제하고 검색 효율을 높일 수 있다. 이 부분이 사실상 Elastic Search를 잘 사용하기 위해서 제일 중요한 부분이라고 생각한다.
3. 쿼리 처리: 사용자가 검색 쿼리를 보낼 때, Elastic Search는 사용된 단어를 토큰화하고, 미리 생성된 역 인덱스를 통해 해당 단어가 포함된 문서를 빠르게 찾아낸다. 이 과정에서 순위 기반 검색(relevance scoring)을 통해 검색 결과의 우선순위를 정리하여, 가장 관련성이 높은 문서를 먼저 반환한다.
4. 분산 구조: Elastic Search는 데이터를 여러 개의 Shard에 분산 저장하고, 각 샤드에서 병렬적으로 검색을 수행한다. 이를 통해 대량의 데이터를 매우 짧은 시간 안에 검색할 수 있다. 또한 Replica 샤드가 존재하여, 읽기 작업을 복제본에서 분산 처리할 수 있어 성능이 더욱 향상된다.
결과적으로, Elastic Search는 인덱스를 생성하고 역 인덱스 구조를 활용함으로써 대규모 데이터 속에서도 매우 빠르고 효율적으로 검색을 수행할 수 있습니다.
2.2 Shard와 Replica
Elastic Search는 데이터를 Shard로 분할하여 저장한다. Shard는 물리적인 데이터 저장 단위로, 하나의 인덱스를 여러 샤드로 나누어 저장함으로써 대규모 데이터를 효과적으로 처리할 수 있다. 예를 들어, 대규모 데이터를 다루는 경우 단일 노드에서 처리하기 어려울 수 있기 때문에, 여러 노드에 샤드를 분산 배치하여 성능을 최적화한다.
샤드는 2가지 유형으로 나뉜다.
- 기본 샤드 (Primary Shard) : 데이터의 기본 저장소 역할을 하며, 각 인덱스에는 최소 하나 이상의 기본 샤드가 존재한다.
- 복제본 (Replica) : 기본 샤드의 복사본으로, 장애가 발생할 경우, 데이터를 안전하게 보존하고, 읽기 성능을 향상시키기 위한 용도로 사용한다. Elastic Search는 기본적으로 각 샤드에 대해 하나 이상의 본제본을 유지할 수있다.
2.3 Mapping과 데이터 삽입
Elastic Search에서 Mapping은 문서 내 각 필드의 구조와 데이터 타입을 정의하는 설정이다. 관계형 데이터베이스에서 스키마에 해당하는 개념으로, 매핑을 통해 어떤 필드가 문자열, 숫자, 날짜 등의 타입인지 명시할 수 있다.
Elastic Search는 다양한 데이터 타입을 지원한다.
- String: 텍스트 데이터로, 분석하여 검색에 사용할 수 있다.
- Number: 정수, 부동 소수점 등 다양한 숫자 타입을 지원한다.
- Date: 시간 정보가 포함된 데이터로, 다양한 포맷을 지원다.
- Geo Point: 위도와 경도를 저장하여 위치 기반 검색에 사용된다.
Elastic Search는 기본적으로 Mapping을 자동으로 생성하지만, 필요한 경우 명시적으로 Mapping을 정의하여 검색 성능을 향상시키거나 필드 분석 방식을 제어할 수 있다.
이외에도 다양한 타입을 지원하며, 특정 객체 내부에 다른 객체가 들어가는 경우, Nested를 사용하여 내부 객체를 타입을 Mapping 할 수 있다.
public class ProjectDocuments implements DistributedLockInterface {
@Id
@Field(name = "id", type = FieldType.Keyword)
private Long id;
@Field(name = "title", type = FieldType.Text)
private String title;
@Field(name = "subject", type = FieldType.Text)
private String subject;
@Field(name = "feature", type = FieldType.Text)
private String feature;
......
@Field(name = "comments", type = FieldType.Nested)
private List<Comment> comments;
......
이런 방식으로 특정 Document 내부에 Nested를 활용하여 데이터 타입을 지정할 수 있다.
3. Elastic Search 최적화
Elastic Search는 대용량 데이터에 대한 검색과 분석을 빠르게 처리할 수 있도록 설계된 시스템이지만, 잘못된 설정이나 인덱스 설계로 인해 성능이 저하될 수 있다. 최적화를 통해 성능을 향상시키고 안정성을 보장할 수 있다.
3.1 인덱스 설계 최적화
Elastic Search의 성능을 최적화하려면 먼저 인덱스 설계를 신중하게 해야 한다. 데이터 구조와 인덱싱 전략은 검색 성능과 자원 사용에 큰 영향을 미친다.
1. 올바른 샤드 크기 설정
Elastic Search는 데이터를 Shard로 분할하여 저장한다. 너무 많은 샤드를 생성하거나 샤드 크기가 너무 크면 성능에 문제가 발생할 수 있다. 적절한 샤드 크기를 설정하는 것이 매우 중요하다.
- 샤드 수 최적화: 샤드가 너무 많으면 오버헤드가 발생하고, 너무 적으면 데이터 분산 효과가 떨어진다. 일반적으로 샤드당 약 10GB~50GB 정도의 데이터를 저장하는 것이 권장된다. 노드 수와 데이터 양에 따라 적절한 샤드 크기와 수를 설정해야 한다.
- 복제본 수 조정: 복제본(Replica)은 데이터 안정성과 읽기 성능을 향상시키는 역할을 한다. 복제본이 많을수록 읽기 성능은 높아지지만, 그만큼 리소스가 많이 소모되므로 복제본 수를 환경에 맞게 조정해야 한다.
2. 매핑 최적화 (필드 타입 설정)
Elastic Search는 문서의 Mapping을 통해 각 필드의 데이터 타입을 지정한다. 잘못된 매핑은 검색 성능을 저하시킬 수 있으므로, 올바른 필드 타입을 정의하는 것이 중요하다.
- 필드 데이터 타입 최소화: 텍스트 분석이 필요하지 않은 필드는 keyword 타입으로 설정하여 인덱스 크기를 줄이고 성능을 최적화할 수 있다. 예를 들어, 제품의 이름이나 설명과 같은 필드에는 text 타입을 사용하지만, 카테고리나 상태와 같이 정확히 일치하는 필드에는 keyword 타입을 사용하는 것이 좋다.
- 필드의 분석기 설정: Analyzer는 텍스트를 분해하여 검색할 수 있는 형태로 변환하는 역할을 한다. 기본 분석기 외에 사용자가 직접 커스텀 분석기를 설정하여 불필요한 분석 작업을 줄이면 성능을 최적화할 수 있다. 예를 들어, Stopwords를 제거하거나, 검색 요구에 맞는 분석기(예: 소문자 변환, Stemming 적용 등)를 적용할 수 있다.
3. 동적 매핑 비활성화
Elastic Search는 기본적으로 새로운 필드를 동적으로 추가할 때 자동으로 매핑을 생성한다. 그러나 너무 많은 필드가 동적으로 추가되면 성능에 부정적인 영향을 미칠 수 있다. **동적 매핑(dynamic mapping)**을 비활성화하거나 제한하여 불필요한 필드 생성을 방지할 수 있다.
index.mapper.dynamic: false
3.2 쿼리 최적화
Elastic Search의 쿼리는 매우 강력하지만, 비효율적으로 작성된 쿼리는 성능 저하를 초래할 수 있다. 쿼리 성능을 최적화하기 위한 몇 가지 방법이 있다.
1. 필터 사용
쿼리에서 Filter를 사용하는 것은 성능을 향상시키는 중요한 방법이다. 필터는 쿼리와 달리 관련성 점수를 계산하지 않으며, 캐싱을 통해 성능을 최적화할 수 있다.
- 정확한 매칭에는 필터 사용: 날짜, 숫자, boolean 값처럼 정확한 매칭이 필요한 경우에는 쿼리 대신 필터를 사용하는 것이 좋다. 예를 들어, 특정 범위의 날짜나 정확한 값에 대한 검색은 필터를 사용하여 쿼리 처리 시간을 줄일 수 있다.
{
"query": {
"bool": {
"filter": {
"term": {
"status": "active"
}
}
}
}
}
2. 필요한 필드만 검색
Elastic Search는 기본적으로 문서의 모든 필드를 반환하지만, 필요 없는 필드를 제외하면 성능을 개선할 수 있다. 특히, 큰 문서에서 모든 데이터를 반환할 필요가 없다면 source 필드 제어를 통해 필요한 데이터만 반환하도록 할 수 있다.
{
"_source": ["name", "price"],
"query": {
"match": {
"description": "search term"
}
}
}
3. 비싼 쿼리 피하기
wildcard, regexp 등의 쿼리는 성능에 큰 영향을 미친다. 특히 대량의 데이터를 검색하는 경우, 이와 같은 비싼 쿼리는 전체 성능에 악영향을 줄 수 있다. 대신 정확한 검색이 필요한 경우 keyword 필드에 대해 정확히 일치하는 검색을 사용하고, 복잡한 정규 표현식이나 와일드카드 사용은 가급적 피해야 한다.
4. 애그리게이션 최적화
애그리게이션은 데이터를 집계하고 요약하는 데 강력한 기능을 제공하지만, 잘못 사용하면 성능 문제가 발생할 수 있다.
- 집계 범위 제한: 애그리게이션을 사용할 때 너무 많은 데이터 범위에서 집계를 수행하면 리소스가 많이 소모된다. 필요하지 않은 데이터는 필터로 제외하고 집계 범위를 적절히 제한하는 것이 좋다
- Cardinality 집계 최소화: Cardinality 애그리게이션(고유값 계산)은 비용이 많이 드는 연산이다. 가능하면 이 집계는 최소한으로 사용하고, 필요한 경우 데이터 모델을 재구성하는 방법을 고려해야 한다.
3.3 캐싱 및 메모리 관리
Elastic Search는 자동으로 캐싱을 사용하여 자주 실행되는 쿼리의 성능을 향상시킨다. 적절한 캐싱 전략을 통해 메모리 사용을 최적화할 수 있다.
1. 필터 캐싱
쿼리에서 필터를 사용할 경우, 필터의 결과는 기본적으로 캐시된다. 캐시는 재사용되므로 동일한 필터 쿼리를 여러 번 실행할 때 성능이 크게 향상된다.
- 필터 쿼리는 성능을 높이기 위해 캐싱을 사용하지만, 너무 자주 변경되는 데이터에는 캐시를 사용하지 않는 것이 좋다. 예를 들어, 자주 업데이트되는 값에는 캐시를 적용하지 않는 것이 성능에 유리하다.
2. JVM 힙 메모리 설정
Elastic Search는 JVM 기반이므로 힙 메모리 설정이 매우 중요하다. JVM 힙 메모리 크기를 잘못 설정하면 **GC(Garbage Collection)**로 인해 성능 저하가 발생할 수 있다.
- 적절한 힙 메모리 크기 설정: 힙 메모리는 너무 크거나 작으면 문제가 발생할 수 있다. 일반적으로 전체 시스템 메모리의 절반을 할당하되, 최대 32GB 이하로 설정하는 것이 좋다. 32GB를 초과하면 JVM이 힙 메모리를 효율적으로 관리하지 못할 수 있다.
- GC 튜닝: Elastic Search는 기본적으로 JVM의 가비지 컬렉터를 사용하지만, 대용량 데이터를 처리할 경우 GC 튜닝이 필요할 수 있다. GC 로그를 분석하고 적절한 설정을 통해 GC로 인한 성능 저하를 최소화해야 한다.
3. 메모리 활용 극대화
Elastic Search는 검색 성능을 높이기 위해 파일 시스템 캐시를 적극적으로 사용한다. 따라서 시스템의 물리적 메모리(RAM)를 최대한 확보하고, 인덱스 데이터를 파일 시스템 캐시에 로드하여 빠른 검색이 가능하도록 해야 한다.
- RAM 활용: 가능한 한 많은 데이터를 메모리에 캐시하여 디스크 I/O를 최소화할 수 있도록 시스템의 RAM 용량을 확장하는 것이 좋다.
3.4 인덱스 관리 전략
Elastic Search의 성능을 유지하려면 인덱스를 효율적으로 관리해야 한다. 오래된 데이터는 주기적으로 삭제하거나 보관 정책을 적용하여 리소스를 절약할 수 있다.
1. 인덱스 롤오버(Rollover)
데이터가 지속적으로 추가되는 로그 데이터와 같은 경우, 하나의 인덱스가 너무 커지면 성능이 저하될 수 있다. Elastic Search의 롤오버 인덱스(Rollover Index) 기능을 사용한다. Elastic Search의 롤오버 인덱스 기능은 일정 조건에 도달하면 새로운 인덱스를 생성하고 데이터를 그곳으로 저장할 수 있도록 한다. 이 방법을 사용하면 대용량의 데이터를 효율적으로 관리할 수 있으며, 인덱스의 크기가 너무 커져 성능 저하가 발생하는 것을 방지할 수 있다.
예를 들어, 인덱스 크기가 50GB에 도달하면 새로운 인덱스로 자동 롤오버를 수행하도록 설정할 수 있다. 이 방법은 특히 로그 데이터와 같은 연속적으로 증가하는 데이터를 처리할 때 유용하다.
POST /my_index/_rollover
{
"conditions": {
"max_age": "7d", // 7일 경과 시 롤오버
"max_size": "50gb" // 50GB를 초과할 시 롤오버
}
}
2. 데이터 보존 정책 (Index Lifecycle Management, ILM)
Elastic Search는 Index Lifecycle Management (ILM) 기능을 통해 오래된 데이터를 자동으로 관리할 수 있다. 이 기능을 사용하면 데이터의 수명 주기를 정의하고, 그에 따라 인덱스를 삭제하거나 보관하는 등의 작업을 자동화할 수 있다. ILM은 일반적으로 로그 데이터나 시간 기반 데이터를 관리할 때 사용된다.
ILM 정책은 크게 네 가지 단계로 구성된다:
- Hot Phase: 데이터를 적극적으로 인덱싱하고 검색하는 단계이다.
- Warm Phase: 덜 자주 검색되는 데이터를 읽기 전용 인덱스로 전환하여 리소스를 절약한다.
- Cold Phase: 오래된 데이터를 저비용 스토리지로 옮기며, 검색 빈도가 낮은 데이터를 효율적으로 관리한다.
- Delete Phase: 데이터가 더 이상 필요하지 않을 경우 인덱스를 자동으로 삭제한다.
PUT _ilm/policy/my_policy
{
"policy": {
"phases": {
"hot": {
"actions": {
"rollover": {
"max_size": "50GB",
"max_age": "30d"
}
}
},
"delete": {
"min_age": "90d",
"actions": {
"delete": {}
}
}
}
}
}
이와 같은 방식으로 ILM을 설정하면, 데이터를 단계별로 관리하고 오래된 인덱스는 자동으로 삭제하여 스토리지를 최적화할 수 있다.
3. 읽기 전용 인덱스
데이터가 변경되지 않는 경우, 인덱스를 읽기 전용(read-only) 상태로 전환하여 성능을 향상시킬 수 있다. 읽기 전용 인덱스는 더 이상 인덱싱 작업이 발생하지 않으므로 리소스 소모가 줄어들고, 검색 성능을 극대화할 수 있다.
PUT /my_index/_settings
{
"index.blocks.write": true
}
이 설정을 통해 인덱스를 읽기 전용으로 전환하고, 불필요한 쓰기 작업을 방지할 수 있다.
3.5 성능 모니터링 및 분석
Elastic Search 클러스터의 상태와 성능을 지속적으로 모니터링하고 분석하는 것은 최적화의 중요한 부분이다. 이를 통해 문제를 사전에 감지하고 성능 저하를 방지할 수 있다.
1. 클러스터 상태 모니터링
Elastic Search는 클러스터의 상태를 모니터링할 수 있는 다양한 API를 제공한다. /_cluster/health API를 사용하여 클러스터, 노드, 샤드의 상태를 실시간으로 확인할 수 있다.
GET /_cluster/health
이 API는 클러스터의 상태(green, yellow, red)를 반환하며, 클러스터가 원활하게 작동하고 있는지 여부를 확인하는 데 사용된다.
2. 노드 및 샤드 상태 모니터링
Elastic Search는 각 노드와 샤드의 성능 지표를 실시간으로 모니터링할 수 있는 API를 제공한다. 이를 통해 리소스 사용 현황을 확인하고, 특정 노드가 과부하 상태에 있는지, 샤드가 불균형하게 분배되었는지 등을 파악할 수 있다.
- 노드 상태 확인: /nodes/stats API를 사용하여 각 노드의 CPU, 메모리, 디스크 사용량을 확인할 수 있다.
GET /_nodes/stats
- 샤드 재할당: 특정 노드에 샤드가 과도하게 할당된 경우, 클러스터의 리밸런싱 작업을 통해 샤드를 재분배하여 부하를 분산할 수 있다.
3. Kibana를 통한 시각화
Elastic Search의 성능을 시각적으로 모니터링하기 위해 Kibana와 같은 도구를 사용할 수 있다. Kibana는 Elastic Search와 통합되어 클러스터의 상태, 인덱스 사용량, 쿼리 성능 등을 직관적으로 시각화해준다.
- Elastic Stack Monitoring: Elastic Search 클러스터의 모든 성능 지표를 모니터링할 수 있으며, CPU 사용량, 메모리 상태, 쿼리 응답 시간 등을 대시보드로 확인할 수 있다.
4. Elastic Search의 한계 및 대안
Elastic Search는 매우 강력하고 확장성이 뛰어난 검색 및 분석 도구이지만, 특정 시나리오에서는 한계점이 존재할 수 있다. 이러한 한계를 이해하고 적절한 해결 방법을 찾거나, 상황에 따라 Elastic Search의 대안을 고려하는 것이 필요하다. 이 섹션에서는 Elastic Search의 주요 한계점과 해결 방법, 그리고 Elastic Search의 대안으로 사용할 수 있는 Solr와 OpenSearch를 비교하여 설명한다.
4.1 Elastic Search의 한계점과 해결 방법
Elastic Search는 다양한 기능을 제공하지만, 몇 가지 주요 한계점이 있다. 이 한계점들을 적절히 해결하지 않으면 성능 저하나 안정성 문제를 겪을 수 있다.
1. 대규모 데이터 관리의 복잡성
Elastic Search는 데이터를 샤드로 분산 저장하므로, 데이터 양이 많아질수록 샤드 및 인덱스 관리를 신중하게 해야 한다. 특히 대규모 데이터를 다루는 경우 샤드의 크기와 복제본 수 등을 잘못 설정하면 성능이 급격히 저하될 수 있다.
- 해결 방법: 샤드 수와 크기를 적절하게 조정하는 것이 중요하다. 인덱스의 크기를 일정하게 유지하기 위해 롤오버 인덱스나 ILM(인덱스 수명 관리) 기능을 사용하여 오래된 데이터를 관리하고, 필요 없는 인덱스를 삭제하거나 보관 정책을 통해 데이터 관리를 자동화할 수 있다.
2. 복잡한 쿼리 성능 저하
Elastic Search는 매우 유연한 쿼리 언어(DSL)를 제공하지만, 복잡한 애그리게이션이나 많은 필드를 포함한 쿼리는 성능에 부정적인 영향을 미칠 수 있다. 특히 정규 표현식, 와일드카드, 고유값 계산 등은 성능이 저하될 수 있는 고비용 연산이다.
- 해결 방법: 복잡한 쿼리를 최적화하기 위해, 필터 기반의 단순한 쿼리로 변환하거나, 필요한 필드만을 검색하여 리소스 사용을 줄일 수 있다. 또한, 쿼리 성능이 낮은 경우 쿼리 프로파일링을 통해 문제의 쿼리를 분석하고 최적화해야 한다.
3. 장기적인 클러스터 관리
Elastic Search 클러스터는 노드가 많아지면서 관리가 점점 복잡해질 수 있다. 특히 장애가 발생할 경우 복구 작업이나 샤드 재배치가 수동으로 이루어질 때 복잡한 설정이 필요할 수 있다.
- 해결 방법: 자동화된 클러스터 관리 도구를 사용하거나, 클라우드 기반의 Elastic Cloud 서비스를 통해 클러스터 관리의 부담을 줄일 수 있다. 또한, 클러스터 모니터링 도구(Kibana나 X-Pack 모니터링)를 활용하여 장애가 발생하기 전에 성능 문제를 예측하고 대응할 수 있다.
4. 고비용 하드웨어 요구
Elastic Search는 대규모 데이터를 빠르게 검색하고 분석하기 위해 많은 메모리와 CPU 자원을 요구한다. 따라서 고성능의 하드웨어가 필요한 경우 운영 비용이 증가할 수 있다.
- 해결 방법: 성능에 영향을 주는 필드 데이터나 애그리게이션 작업을 최소화하고, 쿼리 캐싱을 적극적으로 활용하여 자원 사용을 줄이는 방법을 사용할 수 있다. 또한, 효율적인 인덱스 설계 및 메모리 설정을 통해 리소스 활용도를 최대화할 수 있다.
5. 보안 및 인증 관리
Elastic Search의 기본 설정에서는 보안이 활성화되어 있지 않다. 즉, 외부에서 접근 가능한 환경에서는 보안 문제가 발생할 수 있다. 기본적으로 인증, 접근 제어, 데이터 암호화 기능이 추가 설정 없이 제공되지 않는다.
- 해결 방법: X-Pack이나 Elastic Stack의 보안 모듈을 사용하여 TLS/SSL 암호화, 사용자 인증, 역할 기반 접근 제어(RBAC) 기능을 활성화해야 한다. 이로써 데이터 보안을 강화하고 민감한 정보의 접근을 제한할 수 있다.
하지만, X-Pack을 사용하려면 유료 버전의 Elastic Search를 사용해야한다는 점이 단점으로 꼽힌다. 혼자거나 소규모 프로젝트에서는 상관없지만, 회사입장에서는 보안적인 측면도 고려해야 하기때문에, Elastic Search보다는 다른 대안이 필요하다.
4.2 Elastic Search의 대안 비교
그렇다면, Elastic Search를 대체할 수 있는 도구들은 어떤 도구들이 있을까?
물론 Elastic Search는 강력한 검색 엔진이지만, 특정 시나리오에서는 다른 검색 엔진을 고려할 필요가 있다. 특히 Solr와 OpenSearch는 Elastic Search의 대안으로 자주 언급되는 도구들이다. 각 도구는 고유한 장점과 특징이 있으며, 상황에 따라 더 적합한 선택이 될 수 있다.
1. Apache Solr
Apache Solr는 Elastic Search와 함께 대표적인 오픈 소스 검색 엔진 중 하나이다. Solr는 Apache Lucene 기반으로 개발되었으며, 다수의 기업에서 대규모 검색 시스템을 위해 사용하고 있다. Solr는 특히 정교한 텍스트 검색 및 맞춤형 기능을 제공하는 데 강점을 가진다.
주요 특징
- 고급 텍스트 분석 기능: Solr는 매우 강력한 텍스트 분석 기능을 제공하며, 복잡한 텍스트 처리 및 검색에 강점을 가진다.
- 완성도 높은 UI 관리 툴: Solr는 기본적으로 제공하는 관리자 콘솔이 사용하기 직관적이며 강력한 설정 기능을 제공한다.
- 정교한 데이터 캐싱: Solr는 캐싱 기능이 매우 뛰어나며, 복잡한 쿼리에도 빠른 응답을 제공할 수 있다.
- XML 및 JSON 지원: Solr는 XML 포맷을 기본으로 지원하며, Elastic Search와는 달리 데이터 전송에 있어 XML과 JSON을 모두 사용할 수 있다.
단점
- 분산 처리에 있어 Elastic Search에 비해 상대적으로 복잡하다.
- 확장성과 사용자 편의성이 Elastic Search에 비해 낮다는 평가를 받는다.
2. OpenSearch
OpenSearch는 Elastic Search의 포크(fork) 버전으로, Amazon Web Services(AWS)에서 주도적으로 개발하는 오픈 소스 프로젝트이다. Elastic Search의 라이선스 변경 이후, 자유로운 오픈 소스 사용을 위해 OpenSearch가 탄생하였다. 사실상 동일하다
주요 특징:
- Elastic Search와 높은 호환성: OpenSearch는 Elastic Search 7.10 버전 이후로 포크된 프로젝트이기 때문에, 기존 Elastic Search 사용자에게 익숙한 기능과 인터페이스를 제공한다.
- 완전한 오픈 소스: OpenSearch는 Apache 2.0 라이선스를 따르기 때문에 상업적 사용에 제한이 없다.
- AWS 통합: OpenSearch는 AWS 환경에서 매우 높은 호환성을 제공하며, 특히 Amazon의 관리형 서비스(OpenSearch Service)를 통해 손쉽게 클러스터를 관리할 수 있다.
- 보안 및 모니터링: OpenSearch는 기본적으로 보안, 인증, 모니터링 기능이 포함되어 있어 추가적인 설치나 라이선스가 필요하지 않다.
단점:
- Elastic Search와 완전히 동일하지 않으며, 향후 Elastic Search와의 기능 차이가 더 벌어질 가능성이 있다.
- 커뮤니티와 에코시스템이 Elastic Search에 비해 상대적으로 작다.

[Medium Blog]
[Elasticsearch] Elasticsearch란?
Elasticsearch에 대해서 알아보자.
medium.com
'공부' 카테고리의 다른 글
[Kafka] Kafka Admin과 Admin Client (0) | 2024.11.22 |
---|---|
정규 표현식 Regular Expression (0) | 2024.06.23 |