[Database] Elasticsearch (1)

Bzeromo·2025년 3월 4일
0

DB

목록 보기
8/8
post-thumbnail

⚡ Spring Data Elasticsearch (1)


📌 일단 생존신고

안녕하세요. 오케이홈의 베딩홈 쇼핑몰 백엔드 개발자로 일하느라 오랜 기간 개발 블로그를 유기했습니다. 일과 병행한다는게 쉬운건 아니더라구요?
그리고 일이 끝나고 휴가도 다녀오고... 이제는 본업으로 다시 돌아와야 하지 않나 판단하여 일을 하며 정리했던 것들을 차근차근 올려볼까 합니다.
그동안 어떤 일을 하고 있었는지, 또 무엇을 배우며 성장하고 있었는지 올라오는 글을 보면 알 수 있을만큼 많이 올라올 예정이니 지켜보시면 될듯 합니다.
첫번째는 Springboot 프로젝트에 Elasticsearch을 적용한 사례입니다.
이제 내가 여러분에게 반말을 하겠습니다.


📌 ElasticSearch

⭐ 그게 뭔데?

💡 적용 사유와 방법을 밝히기 전에 우리 블로그에서 Elasticsearch 기술을 자세히 다룬 적이 없기 때문에 이 기술에 대해 간략하게 알아보고 넘어간다. 오래 전에 아주 짧게 다룬 것은 남아있다.

🔷 JSON 문서 기반의 NoSQL 데이터베이스

  • 문서 지향(Document-Oriented)
  • RESTful API를 지원하여 HTTP 기반 API를 통해 데이터 CRUD 및 검색 수행 가능
  • 스키마가 동적으로 변할 수 있어 확장성이 뛰어남(스키마 유연성이라 부른다 카더라)

🔷 분산형 오픈 소스 검색 및 분석 엔진

  • 분산형(Distributed)으로, 여러 노드(서버)로 데이터를 분산하여 저장 및 처리 가능
  • 실시간 검색(Full-Text Search) 지원
  • 데이터 분석 및 통계 연산을 빠르게 수행 가능한 Aggregation 기능을 제공
  • 클러스터링과 샤딩 지원으로 수평 확장이 가능하다는 이점이 있음

💡 샤딩(Sharding)
DB 트래픽을 분산하기 위해 데이터를 조각내 분산 저장하는 데이터 처리 기법으로, 대규모 데이터베이스를 샤드(shard)라고 하는 단위로 분할하는 기술을 일컫는다.

흔히 ELK 스택(Elasticsearch - Logstash - Kibana)이라고 불리는 것이 포함된 Elastic Stack의 핵심 요소로서 빠른 검색, 실시간 데이터 분석, 로그 처리, 추천 시스템 등 다양하게 사용되고 있다.

⭐ 기본 개념

🔹 클러스터(Cluster)

  • 하나 이상의 Elasticsearch 노드(Node)로 구성된 집합
  • 클러스터에는 고유한 이름이 부여되며, 같은 이름을 가진 노드끼리 하나의 클러스터를 형성
  • 모든 데이터를 분산 저장하고 검색 요청을 처리하는 역할을 수행함

🔹 노드(Node)

  • 클러스터에 속하는 개별 서버(Elasticsearch 인스턴스)
  • 노드는 역할에 따라 여러 종류로 구분됨
종류역할
Master Node클러스터 상태 관리 (노드 추가/삭제, 인덱스 관리)
Data Node데이터를 저장하고 CRUD 및 검색 요청 처리
Ingest Node데이터 변환 및 사전 처리 (필요한 경우)
Coordinating Node클라이언트 요청을 받아 적절한 노드로 분배

🔹 인덱스(Index)

  • RDBMS의 데이터베이스(Database)와 유사한 개념
  • 관련된 문서들의 집합이며, 각 인덱스에는 고유한 이름이 있음
  • 하나의 인덱스는 여러 개의 샤드(Shard)로 나뉘어 저장됨

🔹 문서(Document)

  • RDBMS의 Row(행)과 유사한 개념
  • JSON 형식으로 저장되며, 필드(Field)와 값(Value)로 구성
{
  "orderId": "12345",
  "customer": "John Doe",
  "totalAmount": 299.99,
  "orderDate": "2024-03-04T10:30:00",
  "products": [
    {"name": "Laptop", "price": 999.99},
    {"name": "Mouse", "price": 29.99}
  ]
}

🔹 샤드(Shard)

  • 인덱스가 여러 개의 샤드로 나뉘어 저장됨 (수평 확장)
종류역할
Primary Shard원본 데이터를 저장하는 기본 샤드
Replica Shard백업 용도로 사용되며, 장애 발생 시 데이터를 보호

🔹 Mapping (매핑)

  • RDBMS의 스키마(Schema)와 비슷한 개념
  • 필드 타입을 정의 (text, keyword, integer, date 등)
{
  "mappings": {
    "properties": {
      "orderId": { "type": "keyword" },
      "customer": { "type": "text" },
      "totalAmount": { "type": "double" },
      "orderDate": { "type": "date" }
    }
  }
}

⭐ 주요 기능

🔹 Full-Text Search(전문 검색)

  • 역색인(Inverted Index) 구조를 사용하여 검색 속도를 극대화
  • 단순 키워드 검색뿐만 아니라 자연어 처리(NLP), 유사 검색, 오타 보정, 자동완성 등도 지원
{
  "query": {
    "match": {
      "products.name": "Laptop"
    }
  }
}

🔹 Aggregation(데이터 집계 & 통계 분석)

  • SQL의 GROUP BY 같은 Aggregation 기능을 제공
{
  "size": 0,
  "aggs": {
    "category_sales": {
      "terms": { "field": "category.keyword" }
    }
  }
}

🔹 Query DSL (Elasticsearch 전용 검색 쿼리)

  • SQL 대신 JSON 기반의 Query DSL을 사용 가능
{
  "query": {
    "range": {
      "orderDate": {
        "gte": "2024-03-01",
        "lte": "2024-03-04"
      }
    }
  }
}

📌 적용 사유

🔷 우리가 만들어야할 것은 쇼핑몰 이었다.

  • 실시간으로 터져나가는 타 온라인 쇼핑몰들의 사례를 보면서 트래픽 분산 없이는 서버가 목을 매달아버릴 수 있음을 직감했다.

  • 특히 구매 로그는 시간이 지나면서 데이터가 대량으로 증가할 것이 자명한데, RDBMS는 인덱스 최적화 없이 대량 데이터 검색 시 성능 저하가 발생할 수 있었다.

  • 따로 제작한 관리자 페이지에서 회사가 요구한 정보들만을 통계로 담기 위해 Elastic 스택에서 엘라스틱서치만 사용하는 것은 어떨까라는 의견이 기획 초기부터 등장하기 시작했다.

🔷 통계를 위해 요구한 정보의 양이 방대했다.

  • 언제, 누가, 무엇을, 얼마나 구매했는가?
  • 구매 기록은 물론, 환불 및 반품 기록, 가장 많이 팔린 상품 통계 등 RDBMS에 판매 이력을 담았다간 GROUP BY, JOIN, HAVING 같은 연산이 많아져 성능이 구려질 것이 뻔했다.

🔷 회사의 야망은 생각보다 거대했다.

  • 개발 도중에도 실시간으로 커지는 기획은 개발자들을 불안하게 만들었다...
  • 이미 RDBMS 원툴에서 Mongo DB 적용으로 개발 계획을 엎게 되면서 수평 확장과 구조 변경이 유연한 DB가 불안정한 개발 환경에서는 유리함을 깨달아버렸다.
  • 무엇보다, 갑자기 통계 페이지에서 회사가 추가적인 기술 적용으로 변심을 보이면 ELK 스택을 모두 적용할 계획으로 유연하게 갈아타고자 했다.

🔷 통계 Api에서 트랜잭션은 무의미하다 판단!

  • '과거 데이터 기반인데 데이터 정합성을 엄격하게 따질 필요가 있을까?'
  • 조회에 집중되어 있어서 상관없을거라고 판단하여 최종적으로 적용을 진행시켰다.

나중에 얘기하겠지만, 사실 실시간 통계가 주문/결제 데이터와 직접 연결되는 경우에 트랜잭션이 무의미하지 않다... 기술 적용 판단 당시에는 모두가 그렇게 믿었을 뿐, 실제로는 그렇지 않다.


Elasticsearch에 대해, 그리고 이 기술을 적용한 사유에 대해 밝혔다.
다음 포스팅에서 적용 방식과 원리를 밝힌다.

profile
Hodie mihi, Cras tibi

0개의 댓글