ELK에서 Logstash로 저장 시 시간 데이터가 US 시간으로 저장되는 문제 해결

1. 문제 발생

Logstash에서 now를 이용해 시간 데이터를 저장할 때, 기본적으로 미국(US) 시간대로 저장되는 문제가 발생했다. 이는 Kibana에서 데이터를 조회할 때 예상과 다른 시간 값이 표시되는 원인이 되었다.

 

2. 문제 원인

  • Logstash의 기본 타임존(Timezone)이 UTC로 설정되어 있음
    • Logstash는 시간 데이터를 UTC 기준으로 처리하며, 명시적으로 타임존을 설정하지 않으면 기본적으로 UTC가 적용된다.
    • 따라서 한국(KST)에서 저장한 데이터도 9시간이 빠진 UTC 시간으로 저장된다.
  • Elasticsearch도 기본적으로 UTC를 사용
    • Elasticsearch는 시간 데이터를 ISO 8601 형식으로 저장하며, 별도의 변환 없이 UTC 기준으로 처리한다.
    • Kibana에서 데이터를 조회하면 한국 시간(KST)이 아닌 UTC 기준으로 표시될 수 있다.

 

3. 문제 해결책 수립

해결 방법 비교

해결 방법 설명 장점 단점
Logstash에서 타임존 변환 필터를 적용하여 KST로 변환 후 저장 설정이 간단함 데이터 변환 과정 필요
Elasticsearch의 Ingest Pipeline 사용 Ingest Pipeline에서 타임존을 변환 Elasticsearch에서 직접 처리 가능 추가 설정 필요
Kibana에서 시간대 변환 Kibana 설정을 변경하여 한국 시간으로 표시 기존 데이터 수정 불필요 단순 표시만 변경됨

 

4. 문제 해결: Logstash에서 타임존 변환 적용

(1) Logstash에서 타임존 변환 적용

Logstash의 date 필터를 사용하여 UTC → KST 변환을 수행한다.

filter {
  date {
    match => ["@timestamp", "ISO8601"]
    timezone => "Asia/Seoul"
  }
}
  • @timestamp 필드에 대해 ISO 8601 형식을 매칭하여 KST(한국 표준시)로 변환함.
  • 변환된 데이터는 Elasticsearch에 저장될 때 한국 시간으로 반영됨.

(2) Kibana에서 시간대 설정 변경 (보완책)

Logstash에서 변환하지 못한 데이터가 있을 경우, Kibana 설정에서 시간대를 변경할 수 있다.

  1. Kibana 설정 변경:
    • Management → Advanced Settings → dateFormat:tz 값을 Asia/Seoul로 변경.
    • Kibana에서 UTC 시간을 한국 시간(KST)으로 변환하여 표시한다.

 

5. 결론

  • Logstash의 기본 타임존은 UTC이므로, 한국 시간으로 저장하려면 변환 작업이 필요하다.
  • Logstash의 date 필터를 사용하여 Asia/Seoul로 변환하는 것이 가장 효율적인 방법이다.
  • 추가적으로 Kibana 설정을 변경하면 데이터 표시를 한국 시간으로 맞출 수 있다.
  • 이 방식으로 저장된 시간 데이터는 이후 검색 및 분석 시 혼란 없이 사용할 수 있다.

엘라스틱 서치(Elasticsearch) 샤드 관리와 확장성 전략

1. 문제 발생

엘라스틱 서치는 데이터를 저장할 때 샤드(Shard) 단위로 분할하여 저장한다. 샤드의 개수는 검색 성능과 확장성에 큰 영향을 미치며, 이에 대한 적절한 설정이 필요하다.

 

2. 문제 원인

  • 샤드는 병렬 처리를 위한 단위다. 검색 쿼리는 여러 개의 샤드에서 동시에 실행되므로, 샤드 개수를 적절히 설정하면 성능이 향상된다.
  • 예를 들어, 100만 개의 문서를 하나의 샤드에 저장하여 검색하는 것50만 개씩 2개의 샤드에 나누어 병렬로 처리하는 것은 검색 속도에서 차이가 발생한다.
  • 그러나 샤드 개수가 너무 많으면 오버헤드가 증가하여 속도가 오히려 느려질 수 있다.
  • 샤드 관리는 직접적인 성능 최적화와 관련되며, 샤드의 개수와 크기를 조절하는 것이 핵심적인 관리 포인트다.

 

3. 문제 해결책 수립

해결 방법 비교

해결 방법 설명 장점 단점
샤드 개수 증가 데이터를 더 많은 샤드로 분할하여 병렬 처리 읽기 성능 향상 오버헤드 증가, 관리 복잡성 증가
샤드 개수 감소 샤드 수를 줄여 관리 부담 감소 클러스터 안정성 증가 검색 속도 저하 가능
샤드 크기 최적화 적정 샤드 크기를 유지하여 균형을 맞춤 성능 최적화 데이터 볼륨 예측 필요

 

4. 문제 해결: 샤드 크기 최적화 및 ILM 활용

(1) 샤드 크기 설정 기준

  • 엘라스틱 서치 공식 문서에 따르면, 샤드 하나의 크기는 10GB~50GB 사이로 유지하는 것이 권장된다.
  • 적절한 샤드 개수를 계산하는 공식:
  • 샤드 개수 = 예상 인덱스 크기 / 적정 샤드 크기
  • 예를 들어, 예상 데이터 크기가 500GB이고, 샤드 하나의 크기를 50GB로 설정하면, 샤드 개수는 500GB / 50GB = 10개가 된다.
  • 샤드 개수를 설정할 때는 데이터 증가량을 고려하여 유연하게 확장할 수 있도록 설계해야 한다.

(2) ILM(인덱스 수명 주기)와의 관계

  • ILM(인덱스 수명 주기)은 샤드 크기와 직접적인 관계는 없지만, 데이터의 저장 전략을 관리하는 개념으로 샤드 운영을 최적화할 수 있도록 돕는다.
  • Hot-Warm-Cold 노드 구조를 사용하여, 중요하고 자주 사용되는 데이터를 빠른 스토리지에 저장하고, 오래된 데이터는 비용이 저렴한 스토리지로 이동시킬 수 있다.
노드 유형 설명
Hot 노드 최신 데이터 저장, 검색 속도가 가장 빠름
Warm 노드 오래된 데이터 저장, 상대적으로 느린 검색
Cold 노드 압축된 데이터 저장, 읽기 전용
  • ILM을 적용하면 오래된 인덱스를 Cold 노드로 이동하면서, 샤드를 자동으로 병합하거나 크기를 조정하여 리소스를 최적화할 수 있다.
  • 그러나 ILM은 샤드 크기 자체를 조정하는 기능은 없으며, 샤드가 배치되는 노드를 관리하는 역할을 한다.

 

5. 결론

  • 샤드는 검색 성능 최적화를 위해 개수를 적절히 조정해야 하며, 지나치게 많은 샤드는 오버헤드를 증가시킬 수 있다.
  • 샤드 크기는 10GB~50GB 사이로 유지하는 것이 권장되며, 예상 데이터 크기를 기반으로 샤드 개수를 결정해야 한다.
  • ILM(인덱스 수명 주기)은 샤드 크기를 직접 조정하지 않지만, 데이터를 노드별로 분산하여 운영 최적화를 돕는다.
  • 샤드 관리는 검색 성능과 직접적인 관련이 있으며, ILM은 데이터를 장기적으로 효율적으로 보관하는 관리 전략이다.

엘라스틱 서치에 접근해서 데이터를 조회하는 방법은 크게 2가지가 있다.

Repository 방식과 Request(Client API) 방식이 존재한다.

 

Repository는 Spring Data ElasticSearch에서 제공하는 JPA 스타일의 Repository 방식

  • ElasticsearchRepository 또는 ElasticsearchCrudRepository를 상속받아 간단한 CRUD 기능을 제공해 준다. 쿼리를 직접 작성하지 않아도 메서드 네이밍 규칙에 따라 자동으로 생성한다.

Request

RestHighLevelClient(Java API) 또는 직접 HTTP 요청을 보내는 방식(Elasticsearch API)을 사용하여 Elasticsearch를 제어한다.

  • JSON DSL을 직접 사용하여 보다 정교한 검색 및 조작을 수행할 수 있다.

 

결론적으로 Repository는 일반적인 CRUD에서 사용하기 용이하게 디자인 되어 있고, Request는 고급 기능 검색, 예를 들어 집계나 필터를 적용한 검색에 특화되어 있다.

 

실상 현재 프로젝트에서도 이 기준을 가지고 코드가 상황에 맞게 구현이 되어있다. 기술적 의사 결정이라고는 하지만, 실제적으로는 상황에 맞게 2개를 다 사용했다.

 

아래는 상세 내용이다.

 

1. Repository 방식 (Spring Data Elasticsearch)

설명

  • Spring Data Elasticsearch를 활용하여 JPA처럼 Elasticsearch 데이터를 다룰 수 있는 방식.
  • 인터페이스 기반으로 ElasticsearchRepository 또는 ElasticsearchCrudRepository를 상속받아 간단한 CRUD 기능을 제공.
  • 쿼리를 직접 작성하지 않아도 메서드 네이밍 규칙에 따라 자동으로 생성됨.

장점

코드가 간결함: JPA와 유사한 방식으로 CRUD 작업을 간단하게 수행 가능.

빠른 개발 가능: 복잡한 설정 없이 Repository 인터페이스만 정의하면 기본적인 CRUD 기능을 쉽게 사용할 수 있음.

Spring Boot와 통합 용이: Spring의 DI(Dependency Injection)와 연동하여 편리하게 사용 가능.

자동 매핑 지원: 엔티티와 Elasticsearch 문서 간 자동 매핑 지원.

단점

복잡한 쿼리 작성이 어려움: 네이티브 쿼리를 지원하지만, 고도화된 검색 기능을 활용하려면 QueryDSL 또는 커스텀 리포지토리를 사용해야 함.

실행 속도 저하 가능성: 내부적으로 Reflection 및 Proxy를 사용하므로 직접 API를 호출하는 방식보다 성능이 낮을 수 있음.

Elasticsearch의 최신 기능 반영이 늦음: Spring Data Elasticsearch 버전이 Elasticsearch 최신 버전을 지원하지 않을 수 있음.

언제 사용해야 하는가?

✔ CRUD 기능이 대부분이고, 복잡한 검색이 필요하지 않은 경우.

✔ 빠르게 Elasticsearch 연동을 구축해야 하는 경우.

✔ Spring Boot 환경에서 다른 Spring Data와 함께 통합적으로 사용할 경우.

언제 사용하면 안 되는가?

🚫 대량의 데이터를 빠르게 처리해야 할 경우 (Batch 처리).

🚫 고급 검색 기능(예: Aggregation, Multi-Search 등)이 필요한 경우.

🚫 Elasticsearch의 최신 기능(예: Runtime Fields, New Scripting API 등)을 즉시 활용해야 하는 경우.


2. Request(Client API) 방식 (RestHighLevelClient, Elasticsearch API)

설명

  • RestHighLevelClient(Java API) 또는 직접 HTTP 요청을 보내는 방식(Elasticsearch API)을 사용하여 Elasticsearch를 제어.
  • JSON DSL을 직접 사용하여 보다 정교한 검색 및 조작 가능.

장점

유연한 쿼리 작성: Elasticsearch의 강력한 Query DSL을 직접 활용할 수 있음.

고급 검색 기능 지원: Aggregation, Nested Query, Multi-Search 등 복잡한 검색 기능을 사용할 수 있음.

최신 Elasticsearch 기능 활용 가능: Elasticsearch 버전과 관계없이 모든 API를 직접 호출 가능.

높은 성능: 직접 API를 호출하므로 Spring Data Elasticsearch의 Overhead가 없음.

단점

코드가 복잡해질 수 있음: JSON 기반의 Query DSL을 직접 작성해야 하므로 가독성이 떨어질 수 있음.

Spring Boot와 통합성이 낮음: RestHighLevelClient는 Spring의 Repository 방식처럼 자동 매핑이 되지 않음.

직접 데이터 매핑 필요: Elasticsearch에서 가져온 데이터를 직접 DTO나 Entity로 변환해야 함.

언제 사용해야 하는가?

복잡한 검색 로직이 필요한 경우 (예: Aggregation, Full-text Search, Multi-Search).

대량의 데이터 처리 (Batch Insert, Bulk Processing 등).

Elasticsearch 최신 기능을 즉시 활용해야 하는 경우.

언제 사용하면 안 되는가?

🚫 단순한 CRUD 위주의 서비스에서 불필요하게 복잡성을 증가시키는 경우.

🚫 Spring Boot 기반 프로젝트에서 JPA 스타일의 간단한 연동이 필요한 경우.

🚫 Elasticsearch와의 연동이 적고, 관리할 코드의 복잡성을 줄이고 싶을 경우.


3. Repository 방식 vs Request(Client API) 방식 차이점 정리

비교 항목 Repository 방식 (Spring Data Elasticsearch) Request(Client API) 방식 (RestHighLevelClient, Elasticsearch API)

개발 편의성 ✅ 간편한 CRUD 제공 ❌ 직접 Query DSL 작성 필요
복잡한 쿼리 지원 ❌ 제한적 (QueryDSL 또는 커스텀 필요) ✅ 완전한 Query DSL 지원
성능 ❌ Proxy 및 Reflection으로 인해 느릴 수 있음 ✅ 직접 API 호출로 최적화 가능
Spring Boot 통합 ✅ Spring Data 방식 지원 ❌ 직접 설정 필요
최신 기능 지원 ❌ Spring Data 버전 의존 ✅ 최신 API 즉시 활용 가능
대량 데이터 처리 ❌ 적합하지 않음 ✅ Bulk API 지원

4. 결론: 언제 어떤 방식을 선택해야 하는가?

Repository 방식(Spring Data Elasticsearch) 추천 경우

  • 기본적인 CRUD 작업이 대부분인 경우.
  • Spring Boot 프로젝트에서 빠르고 간편하게 Elasticsearch를 연동하고 싶은 경우.
  • 데이터 검색이 단순하고, 최신 Elasticsearch 기능을 활용할 필요가 없는 경우.

Request(Client API) 방식 추천 경우

  • 복잡한 검색이 필요한 경우(Aggregation, Multi-Search, Nested Query 등).
  • 대량의 데이터를 빠르게 처리해야 하는 경우(Bulk Processing, High Throughput 요구).
  • Elasticsearch 최신 기능을 즉시 활용해야 하는 경우.

5. 결론 요약

  • 간단한 CRUD, 빠른 개발Spring Data Elasticsearch (Repository 방식)
  • 고급 검색, 대량 데이터 처리Request(Client API) 방식
  • 둘을 혼합해서 사용 가능 → 기본 CRUD는 Repository 방식, 복잡한 쿼리는 Client API 방식

 

엘라스틱 서치(Elasticsearch)를 선택한 이유

1. 문제 발생

프로와 학생의 매칭 사이트를 개발하는 과정에서, 감성 분석을 활용해 인기 상품과 강사를 추천하는 기능을 구현하고자 했다. 하지만 처음 사용한 MySQL의 LIKE 연산자를 이용한 문장 검색은 상당히 느린 속도를 보였다.

해당 기능은 추후 개인에 맞춰서 구성할 계획이었다보니, 개개인마다 느린 추천 검색을 수행하는 형태는 서비스를 운영하는 것에 있어 큰 마이너스 요인이 될 수 있을 것이라 판단하게 되었다.

2. 문제 원인

  • 기본적인 인덱스 구조는 문서 단위 검색 방식을 사용한다.
  • 검색 과정:
    1. 문서1을 연다.
    2. 문서1 안에 특정 단어가 있는지 찾는다.
    3. 문서2로 넘어간다.
    4. 이 과정을 반복.
  • MySQL에서는 모든 문서를 개별적으로 조회하고 검색해야 하므로 속도가 느려진다.
  • 이는 저장 방식 자체의 문제이므로, 해결하기 위해서는 카테고리화를 하거나 역색인(Inverted Index) 방식을 도입해야 했다.

 

3. 문제 해결책 수립

해결 방법 비교

해결 방법 설명 장점 단점
카테고리화 (태그 기반 검색) 데이터를 사전에 특정 키워드나 카테고리로 분류하여 검색 검색 속도 향상 새로운 키워드 추가 시 재구축 필요
MySQL FULLTEXT INDEX MySQL에서 제공하는 기본적인 전문 검색 인덱스 기존 DB와 쉽게 통합 여전히 속도가 느리고, 대량 데이터에서 비효율적
NoSQL (MongoDB 등) + 검색 엔진 NoSQL 기반 문서 저장과 내부 검색 기능 사용 RDB보다 확장성이 좋음 여전히 전문 검색 성능 부족
엘라스틱 서치(Elasticsearch) 역인덱스 구조를 활용한 전문 검색 엔진 빠른 검색 속도, 실시간 분석 가능 추가적인 시스템 관리 필요

 

4. 문제 해결: 엘라스틱 서치 도입

엘라스틱 서치는 역인덱스(Inverted Index) 구조를 사용하여 검색 속도를 획기적으로 개선한다.

  • 빠른 검색 속도: 데이터가 많아도 색인이 최적화되어 있어 검색이 빠름
  • 비정형 데이터 지원: JSON 기반 데이터 저장으로 다양한 문서 형태 지원
  • 실시간 색인화 및 분석: 새로운 데이터가 추가되더라도 검색 속도에 영향을 받지 않음
  • 분산 처리 지원: 여러 개의 노드에 데이터를 분산하여 확장 가능

결론: MySQL의 LIKE 검색은 대량 데이터에서 성능이 저하되는 문제가 있으며, 이를 해결하기 위해 역색인(Inverted Index)을 기반으로 한 엘라스틱 서치를 도입하면 문장 검색 속도를 획기적으로 향상시킬 수 있다.

+ Recent posts