깨록

OpenSearch의 기본적인 물리적, 논리적 구조 관계를 정리해보았습니다. 본문

개발하다

OpenSearch의 기본적인 물리적, 논리적 구조 관계를 정리해보았습니다.

쓰온 2024. 11. 24. 11:10

글을 시작하며

업무에서 데이터 로그를 모아 빠르게 검색하는 시스템을 만들기 위해 OpenSearch를 도입한 경험이 있습니다.

 

당시에는 제대로 이해하고 사용하기보다 빨리 적용 시키기 위해 다른 사람들이 진행한 방식을 복사, 붙여넣기만 했었는데 제대로 운영하고 사용하기 위해 그 개념에 대해 간단히 정리해보려고 합니다.

 


예상 독자

주요 대상으로는 OpenSearch를 처음 시작하는 개발자기본 설치와 사용 경험이 있으나 개념 정립이 필요한 사람입니다.

 

OpenSearch에 대한 이해가 이미 있거나 고급 설정과 운영에 대한 깊은 지식이 필요한 경우에는 좀 더 전문적인 글이나 공식문서를 추천드립니다!

 


1. OpenSearch의 시작 : 검색 엔진의 도입 과정

1.1 일상 예시

먼저 간단하게 우리가 도서관에서 책을 찾는 경우를 생각해보겠습니다.

 

작은 도서관이라면 책장 사이를 직접 돌아다니며 원하는 책을 찾을 수도 있겠지만,

책이 수 십만 권 이상 있는 큰 도서관이라면 더 효율적이고 빠르게 원하는 책을 찾기 위해 도서관에 있는 도서 검색 시스템을 사용할 것 입니다.

이미지 출처 : chatGPT - DALL·E

 

1.2 데이터 처리 환경의 변화

우리가 원하는 책을 찾듯이 기업은 원하는 데이터를 데이터 보관소에서 찾아서 사용자에게 제공하거나 필요한 곳에 사용합니다.

 

데이터의 양이 적은 경우에는 기존 시스템대로 운영했지만 “전자상거래 사이트의 수백만 개의 상품 정보”, “SNS의 수많은 게시글과 댓글”들과 같이 엄청난 양의 데이터가 생겨나게 됩니다.

 

이로인해 이전에 비해 기업들이 다루는 데이터의 양이 폭발적으로 증가하게 되어 더 효율적인 처리방법을 찾게 되었습니다.

 

1.3 RDBMS의 한계

기존에는 이러한 데이터를 전통적인 관계형 데이터베이스(RDBMS)로 관리해왔지만 여러 한계가 존재했습니다.

  1. 검색 성능의 한계
    • RDBMS는 정확한 값 매칭에 강하지만, ‘비슷한’ 내용을 찾는 것은 매우 비효율적입니다.
    • 긴 문장 속에서 특정 키워드를 찾는 작업이 매우 느립니다.
  2. 대용량 처리의 어려움
    • 데이터가 증가할수록 검색 속도가 급격히 저하
    • 실시간 검색과 분석이 사실상 불가능
  3. 비정형 데이터 처리의 한계
    • 정해진 형식이 없는 문서, 로그 등의 처리가 어려움
    • 다양한 형태의 데이터를 유연하게 저장하고 검색하기 어려움

 

1.4 Elasticsearch의 등장

RDBMS의 한계점들을 해결하는 대안으로 Elasticsearch 검색 엔진이 등장합니다.

Elasticsearch는 Apache Lucene라는 검색 라이브러리를 기반으로 만들어졌으며, 다음과 같은 기능들을 제공합니다.

  1. 강력한 전문 검색 기능
    • 자연어 검색 지원
    • 오타 교정 기능
    • 관련어 확장 검색
  2. 실시간 처리 능력
    • 데이터가 입력되자마자 바로 검색 가능
    • 실시간 로그 분석과 모니터링 가능
  3. 분산 시스템 구조
    • 서버를 추가하는 것만으로 손쉽게 용량과 성능 확장 가능
    • 장애가 발생해도 서비스 중단 없이 운영 가능

 

1.5 OpenSearch의 탄생

그러던 중 2021년 Elasticsearch의 라이센스 정책이 변경되면서 사용에 제한이 생기게 되었고, 이때 AWS에서 Elasticsearch의 마지막 오픈소스 버전(7.10.2)을 기반으로 OpenSearch라는 검색 엔진을 만들어 사용하게됩니다.

 

 


2. 핵심 키워드와 구조

OpenSearch에 대해 이야기하기전에 핵심적으로 알아야하는 키워드들에 대해서 간략하게 비유를 들어가며 설명해보도록 하겠습니다.

저는 해당 개념들을 물리적인 구조의 개념과 논리적인 구조의 개념으로 구분지어 정리해보았습니다.

 

2.1 물리적 구조

cluster와 node, 그리고 shard의 관계를 정리한 이미지입니다.

2.1.1 Cluster

OpenSearch에서 Node들의 집합을 Cluster라고 합니다.

 

Cluster는 여러 개가 존재할 수 있지만 각 Cluster는 완전히 독립적인 시스템으로 동작하기 때문에, 다른 Cluster와 데이터 공유나 통신을 주고받지 않습니다.

이러한 독립성으로 하나의 네트워크 내에서도 개발용, 운영용 등을 나누어서 동시에 여러 Cluster를 운영할 수 있습니다.

 

Cluster는 Node를 자동으로 감지하고 관리합니다.

같은 네트워크 대역에서 Node를 생성할 때 cluster.name 설정으로 클러스터를 구분합니다.

새로운 Node가 생성되면 동일한 cluster.name을 가진 클러스터에 자동으로 편입됩니다.

 

즉, Cluster는 독립성이 보장되어 하나의 네트워크에 여러 개의 Cluster를 운영할 수 있고 복잡한 설정없이 Cluster에 자동으로 편입시키고, 네트워크 장애가 발생한 후 복구될 때 자동으로 Cluster가 재구성되는 특징을 가집니다.

 

 

2.1.2 Node

이미지 출처 : https://opensearch.org/docs/latest/tuning-your-cluster/

 

Node는 OpenSearch에서 Cluster를 구성하는 하나의 실행 단위 입니다.

 

Node는 역할에 따라 3가지로 구분할 수 있습니다. 이해하기 쉽도록 “매장”의 비유와 함께 살펴보겠습니다.

  1. Master Node클러스터의 ‘관리자’ 역할을 하는 노드로, 클러스터의 전반적인 상태를 관리하고 인데스 생성/삭제와 같은 클러스터 수준의 변경 사항을 관리합니다. 매장에 비유하자면 매장 전체를 관리하는 점장님같은 느낌입니다.
  2. Data Node문서의 저장, 검색, 수정, 삭제 등의 데이터 작업을 수행하고 검색, 집계 처리 작업도 진행합니다. 또한 저장된 데이터의 색인 작업도 진행합니다. 매장의 상품을 보관하고 고객 요청에 따라 상품을 찾아주는 직원과 같은 역할을 합니다.
  3. Coordinating Node클라이언트의 요청을 접수하고 요청을 적절한 데이터 노드에 분배하고 여러 노드로부터 받은 결과를 합쳐서 반환합니다. 매장의 안내 데스크와 같이 고객의 요청을 받아서 적절한 부서로 안내하고 최종 응대를 하는 역할을 합니다.

Node를 역할별로 나누어보았는데 꼭 하나의 Node가 하나의 역할을 가져야하는 것은 아닙니다.

하나의 Node가 여러 역할을 동시에 수행할 수 있습니다.

 

그래서 처음에 특별한 설정없이 Node를 생성하면 해당 Node는 모든 역할을 수행합니다.

이후에 Cluster에 상황에 따라 마스터 Node가 자동으로 선출됩니다.

 

2.1.3 Shard

이미지 출처 : https://aws.amazon.com/ko/blogs/tech/opensearch-sizing/

 

Shard는 마치 큰책을 여러 권으로 나누어 저장하듯이 Index의 데이터를 나누어 저장하는 단위입니다.

 

각 Shard는 하나의 Lucene 인덱스로 동작하며, 그 안에 실제 데이터(Document)들이 Segment 단위로 저장됩니다.

 

쉽게 말해, Shard는 데이터를 물리적으로 분산 저장하기 위한 단위라고 할 수 있습니다.

 

도서관으로 비유하자면, 하나의 큰 도서관인 Index가 존재하면, 여러 개의 분관인 Shard로 나누어져 있고, 각 분관에 여러 개의 책장인 Segment 안에 실제 책들인 Document가 저장되는 형식입니다.

 

OpenSearch에서는 Shard를 원본 데이터를 저장하는 Primary Shard와 복사본을 저장하는 Replica Shard 두가지 형태로 구분합니다.

 

shard는 primary shard와 replica shard를 가지고 replica는 다른 노드에 존재한다.

 

이렇게 데이터를 Shard 단위로 관리하면, 대용량 데이터를 여러 서버에 분산해서 저장할 수 있고, 동시에 여러 곳에서 검색할 수 있어 검색 속도도 빨라집니다.

 

또 하나의 서버에 문제가 발생해도 다른 서버의 복사본으로 운용할 수 있습니다.

 

2.2 논리적 개념

2.2.1 Index

OpenSearch에서 Index는 비슷한 성격을 가진 Document들의 모음입니다.

 

마치 도서관에서 소설과 전문 서적을 구분지어 관리하는 것과 비슷합니다.

 

Index에 저장된 데이터는 내부적으로는 여러 Shard로 나뉘어 저장되지만, 사용자는 이를 신경쓰지 않고 단일 저장소와 같이 사용할 수 있습니다.

 

2.2.2 Document

Document는 데이터를 저장하는 기본 단위입니다.

 

JSON 형태로 저장되는 실제 데이터이며, 여러 필드(Field)로 구성됩니다.

 

예를 들어, 쇼핑몰의 상품 Document의 예시를 만들어보겠습니다.

{
    "id": "1234",
    "name": "맥북 프로 16인치",
    "price": 3600000,
    "category": "노트북",
    "description": "최신형 프로페셔널 노트북",
    "created_at": "2024-01-15"
}

위처럼 id, name, price와 같은 필드가 존재하고, 해당 필드는 용도에 맞는 데이터 타입을 가집니다.

 

예시에서는 id와 name은 텍스트형을 price는 숫자형 타입을 가지는 것을 볼 수 있습니다.

 

2.2.3 Mapping

Index에 저장될 Document의 구조를 정의하는 것을 Mapping이라고 합니다.

 

예를 들어, 위에서 만들었던 상품 Document 예시의 Mapping을 정의해보겠습니다.

{
    "properties": {
        "name": { 
            "type": "text",      // 검색 가능한 텍스트 형태
            "fields": {
                "keyword": {     // 정확한 일치 검색용
                    "type": "keyword"
                }
            }
        },
        "price": { 
            "type": "integer"    // 숫자 형태
        },
        "created_at": { 
            "type": "date"       // 날짜 형태
        }
    }
}

Mapping을 통해 각 필드의 데이터를 어떻게 저장하고 검색할 지 결정합니다.

 

이러한 Mapping으로 각 필드의 특성에 맞는 최적화된 검색과 분석을 제공합니다.

 

2.2.4 Inverted Index

역인덱스라고 불리는 Inverted Index는 OpenSearch에서 빠른 검색을 가능하게 하는 핵심 구조입니다.

 

일반적인 데이터 저장 방식과 역인덱스를 비교해보겠습니다.

 

먼저 일반적인 방식입니다.

[일반적인 저장 방식]
문서1: "맛있는 초콜릿 케이크"
문서2: "달콤한 초콜릿 쿠키"
문서3: "고소한 치즈 케이크"

 

다음은 역인덱스 방식입니다.

[역인덱스 구조]
초콜릿 → 문서1, 문서2
케이크 → 문서1, 문서3
달콤한 → 문서2
고소한 → 문서3
치즈 → 문서3

 

위처럼 역인덱스 방식은 “초콜릿”이라는 키워드가 포함된 문서를 찾을 때 모든 문서를 일일이 확인할 필요 없이 바로 문서1과 문서2를 찾을 수 있습니다.

 

이런 구조 덕분에 OpenSearch는 대량의 데이터에서도 빠른 검색이 가능합니다.

 

 


3. 알아두면 유용한 사용 예시

앞서 설명한 내용들을 바탕으로 실제 OpenSearch를 사용하는 예시를 간단히 알아보도록 하겠습니다.

 

도서관 시스템을 예로 들어 설명해보도록 하겠습니다.

 

3.1 기본적인 CRUD 작업 예시

도서관에서 책을 관리하듯 OpenSearch에서도 데이터를 등록하고, 찾아보고, 수정하고, 삭제하는 기본적인 작업들이 필요합니다.

 

3.1.1 Create

새로운 책(데이터)를 등록하는 방법은 다음과 같습니다.

// POST /books/_doc
{
    "title": "OpenSearch 시작하기",
    "author": "김검색",
    "published_date": "2024-01-15",
    "category": "기술"
}

3.1.2 Read

책(데이터)의 고유번호로 책의 정보를 찾아볼 수 있습니다.

// GET /books/_doc/1
// ID가 1인 도서 정보 조회

3.1.3 Update

책이 대출되었을 때 그 정보를 수정하듯이 특정 데이터의 정보를 수정합니다.

// POST /books/_update/1
{
    "doc": {
        "status": "대출중"
    }
}

3.1.4 Delete

더이상 보관하지 않는 책(데이터)는 삭제합니다.

// DELETE /books/_doc/1
// ID가 1인 도서 정보 삭제

 

3.2 전문 검색을 사용하는 방법

책을 찾을 때 제목이나 내용의 일부만 기억이 나는 경우에 사용할 수 있는 방법이 바로 “전문 검색” 방법입니다.

 

다음은 책의 제목이나 내용으로 검색하는 예시입니다.

// GET /books/_search
{
    "query": {
        "match": {
            "title": "OpenSearch 입문"
        }
    }
}

 

여러 필드(예시에서는 제목과 설명)를 동시에 검색하는 경우 다음과 같이 작성합니다.

// GET /books/_search
{
    "query": {
        "multi_match": {
            "query": "검색 기술",
            "fields": ["title", "description"]
        }
    }
}

 

3.3 통계 내기(집계)

데이터를 운용하다보면 데이터들의 통계가 필요할 때가 존재합니다.

 

다음은 OpenSearch에서 데이터 통계를 내는 방법입니다.

 

분야별로 책이 몇 권씩 있는지 확인하는 방법은 다음과 같습니다.

// GET /books/_search
{
    "size": 0,
    "aggs": {
        "category_count": {
            "terms": {
                "field": "category.keyword"
            }
        }
    }
}

 

다음은 월별로 새로 들어온 책이 몇 권인지 확인하는 예시입니다.

// GET /books/_search
{
    "size": 0,
    "aggs": {
        "books_per_month": {
            "date_histogram": {
                "field": "published_date",
                "calendar_interval": "month"
            }
        }
    }
}

 

3.4 시스템 로그 분석하기

도서관에서 책에 대한 정보만 다루는 것이 아니라 도서관 이용 기록과 같은 데이터를 다루는 것처럼, 시스템의 동작 상태도 기록하고 분석할 수 있습니다.

 

먼저 로그를 저장하는 방법은 다음과 같습니다.

// POST /logs/_doc
{
    "timestamp": "2024-01-15T10:30:00",
    "level": "ERROR",
    "message": "데이터베이스 연결 실패",
    "service": "user-api"
}

 

문제가 있는 로그를 보는 방법입니다.

// GET /logs/_search
{
    "query": {
        "match": {
            "level": "ERROR"
        }
    }
}

 

시간대별로 로그가 얼마나 발생했는지 확인하는 방법입니다.

// GET /logs/_search
{
    "size": 0,
    "aggs": {
        "logs_over_time": {
            "date_histogram": {
                "field": "timestamp",
                "fixed_interval": "1h"
            }
        }
    }
}

 

이처럼 기본적인 사용방법들을 바탕으로 더 전문적이고 복잡한 검색이나 분석도 가능합니다.

 

 


요약 & 대표적인 사용 사례

OpenSearch는 Cluster, Node, Shard라는 물리적 구조와 Index, Document 등의 논리적 구조를 가진 분산 검색 엔진입니다.

마치 여러 분관을 가진 도서관 시스템처럼, 대용량 데이터를 효율적으로 저장하고 검색할 수 있습니다.

특히 데이터를 자동으로 분산 저장하고, 장애가 발생해도 서비스를 계속할 수 있는 안정성이 큰 장점입니다.

 

OpenSearch는 다양한 분야에서 활용됩니다.

쇼핑몰의 상품 검색 시스템, 로그 데이터 분석 도구, 게시글 검색 엔진 등으로 사용되고 있습니다. 특히 데이터의 실시간 검색이 필요하거나, 대량의 데이터를 분석해야 하는 경우에 강점을 보입니다.

 

 


글을 마치며

어떤 기술을 사용하기에 앞서 구조적인 이해가 필요하다고 생각해서 해당 내용을 정리하게 되었습니다.

처음에 Index와 Shard의 관계, Cluster와 Node의 관계 등 처음에는 헷갈리는 내용에 서로간의 관계도 제대로 이해되지 않았지만, 지금은 정리를 통해 조금 알아간 것 같습니다.

물론 정리 중에 제가 잘못이해해서 작성된 부분이 있을 수 있습니다. 해당 내용에 대해서는 편하게 댓글 남겨주시면 확인하고 수정하도록 하겠습니다.

감사합니다.