HooneyLog
© 2026 Seunghoon Shin. All rights reserved.
모든 게시글
기타
2026. 3. 28.•
2

검색 성능의 혁신: Elasticsearch 도입으로 검색 지연 시간 40배 개선하기

Seunghoon Shin
작성자 Seunghoon Shin풀스택 개발자

검색 성능의 혁신: Elasticsearch 도입으로 검색 지연 시간 40배 개선하기

1. 문제의 배경

서비스의 규모가 커지고 데이터가 수백만 건 이상 쌓이기 시작하면, 가장 먼저 성능 한계가 드러나는 곳 중 하나가 바로 검색 기능입니다.

우리가 흔히 사용하는 PostgreSQL이나 MySQL 같은 관계형 데이터베이스(RDBMS)에서 LIKE '%keyword%' 쿼리를 실행하면, DB 엔진은 테이블의 모든 행을 하나씩 훑어야 하는 Full Table Scan을 수행합니다. 데이터가 적을 때는 문제가 없지만, 수백만 개의 상품이나 게시글이 쌓인 상태에서 동시 접속자가 늘어나면 검색 쿼리 하나가 2초 이상 걸리게 되고, 이는 곧 전체 시스템의 병목 현상으로 이어집니다.

2. 해결 방안 탐색

이러한 검색 성능 문제를 해결하기 위해 크게 세 가지 대안을 고려했습니다.

  1. RDBMS Full Text Index: 설정이 간편하지만 한글 형태소 분석의 정교함이 떨어지고, 데이터가 늘어날수록 성능 향상폭이 제한적이었습니다.
  2. Redis를 활용한 검색 캐싱: 자주 검색되는 키워드는 빠르지만, 새로운 검색어나 복잡한 필터링 조건에는 대응할 수 없었습니다.
  3. Elasticsearch 도입: 루씬(Lucene) 기반의 분산 검색 엔진으로, 텍스트 검색에 최적화된 역색인(Inverted Index) 구조를 사용합니다.

대규모 데이터에 대한 실시간 검색과 정교한 한글 분석(Nori 등)이 필수적이었기에, 우리는 Elasticsearch를 최종 솔루션으로 채택했습니다.

3. 핵심 개념 및 아키텍처

Elasticsearch가 RDBMS보다 수십 배 빠른 이유는 데이터를 저장하는 방식 자체가 다르기 때문입니다.

역색인 (Inverted Index) 구조

책의 맨 뒷부분에 있는 '찾아보기' 페이지를 생각하면 쉽습니다. 일반적인 DB가 "문서 번호 -> 내용" 순서로 저장한다면, Elasticsearch는 "단어 -> 그 단어가 포함된 문서 번호들"의 형태로 데이터를 저장합니다. 따라서 특정 단어를 검색할 때 모든 데이터를 훑을 필요 없이, 단어가 등록된 위치로 즉시 점프하여 결과를 찾아냅니다.

분산 처리 및 고가용성

Elasticsearch는 여러 대의 서버(Node)를 하나의 클러스터로 묶어 데이터를 분산 저장(Sharding)합니다. 특정 서버에 장애가 발생해도 복제본(Replica)을 통해 서비스 중단 없이 작동하는 탄탄한 아키텍처를 가지고 있습니다.

4. 구현 및 트러블슈팅

NestJS 환경에서 Elasticsearch 클라이언트를 연동하고 상품을 검색하는 기본적인 흐름은 다음과 같습니다.

// elasticsearch.service.ts import { Injectable } from '@nestjs/common'; import { ElasticsearchService } from '@nestjs/elasticsearch'; @Injectable() export class ProductSearchService { constructor(private readonly esService: ElasticsearchService) {} async searchProducts(query: string) { // Elasticsearch의 match 쿼리를 사용한 전문 검색 const result = await this.esService.search({ index: 'products', body: { query: { multi_match: { query, fields: ['title', 'description', 'category'], fuzziness: 'AUTO' // 오타 교정 기능 포함 } } } }); return result.hits.hits.map(item => item._source); } }

트러블슈팅: 데이터 동기화 문제

Elasticsearch 도입 시 가장 까다로운 부분은 RDBMS와의 데이터 일관성 유지였습니다. DB에서 상품명이 수정되었는데 검색 엔진에는 옛날 이름이 남아있는 현상이 발생했죠.

이를 해결하기 위해 우리는 Logstash를 활용한 배치 동기화와, 데이터 변경 시점에 MQ(Message Queue)를 사용하여 실시간으로 인덱스를 갱신하는 방식을 병행하여 데이터 정합성 문제를 해결했습니다.

5. 결과 및 Trade-off

도입 전후의 지표 변화는 매우 극적이었습니다.

  • 검색 속도: 평균 2.1s에서 48ms로 약 43배 향상되었습니다.
  • 검색 품질: 단순 일치 검색에서 벗어나 형태소 분석기를 통한 유의어 검색 및 오타 교정이 가능해졌습니다.

얻은 것과 잃은 것(Trade-off): 하지만 Elasticsearch는 메모리를 매우 많이 점유(JVM Heap)하며, 운영을 위한 인프라 비용이 추가로 발생합니다. 또한, 실시간성(Real-time)이 아닌 Near Real-time(약 1초의 지연) 구조이므로, 데이터 입력 즉시 검색 결과에 나오지 않을 수 있다는 점을 반드시 설계 시 고려해야 합니다.

6. 마치며

검색은 사용자가 우리 서비스의 가치를 가장 먼저 경험하는 창구입니다. 단순한 기능 구현을 넘어 Elasticsearch와 같은 전문 도구를 도입하는 것은 사용자 경험을 한 단계 끌어올리는 아주 중요한 엔지니어링 결정입니다.

성능 병목으로 고민하고 계신다면, 지금 바로 여러분의 서비스에 검색 엔진이라는 날개를 달아보시는 건 어떨까요?

← 이전 글Next.js 렌더링 전략 완벽 가이드: SSR, SSG, ISR부터 RSC까지
다음 글 →NestJS에서 직렬화와 역직렬화 완벽 가이드: DTO와 class-transformer의 마법