지나공 : 지식을 나누는 공간
Elasticsearch 와 Lucene 본문
지금 opensearch 를 운영 중인데 쿼리나 운영이 서툴러서 쿼리를 좀 기록하려 했다가... 클러스터 내용을 빠뜨리고 바로 쿼리에 대해 쓰기가 좀 아쉬워서 결국 chapter 1 같은 내용부터 쓴다. 전에 한참 elasticsearch를 전혀 모르고 책의 딱 챕터1만 읽었던 시절, 루씬과 엘라스틱서치가 여기저기 나와서 이게 뭔가 싶었다. 근데 시니어 분이 '그냥 Lucene을 감쌌을 뿐이다.' 라고 하셨는데, 그 말이 무슨 말인지 알겠다..ㅎ
ElasticSearch 와 Opensearch
Elastic 에서 Apache Lucene 을 기반으로 만든 검색 엔진으로, 여러 서버에 분산해서 데이터를 저장하고 노드 추가를 통한 수평 확장이 가능하다. 7.11 버전부터는 오픈소스가 아니고 상용 라이선스로 제공된다. Opensearch 는 Elasticsearch 와 Kibana의 오픈소스 포크고, 회사에서 현재는 opensearch를 사용하고 있다.
Lucene 과 Elasticsearch
Elasticsearch를 알려면 Lucene 을 알아야 한다. Lucene 은 elasticsearch와 opensearch 의 코어 라이브러리이자 오픈소스 검색 라이브러리이다. 루씬 자체는 단일 노드에서만 작동하고, 분산 처리를 지원하지 않고, 클러스터링 기능도 없지만 엘라스틱서치는 Lucene을 기반으로 분산, 클러스터링, RESTful API 등을 추가해서 제공한다.
루씬의 기본적인 동작은 인덱싱과 검색이다.
- 인덱싱: 데이터를 역인덱스(reverse index) 형식으로 변환하여 저장한다. 각 문서(Document)는 키워드와 매핑되는 단어의 위치를 포함한 정보로 저장된다.
- 검색: 사용자가 검색어를 입력하면, Lucene은 역인덱스를 검색하여 해당 키워드와 일치하는 문서들을 찾아 반환한다.
Elasticsearch 동작은 Lucene 에 기반한 분산환경 동작이다.
- 클러스터: Elasticsearch는 여러 대의 서버에서 클러스터를 구성하여 동작한다. 각 서버는 노드로 구성되며, 데이터를 분산하여 저장하고 처리한다.
- 샤딩과 리플리카: 데이터는 샤드(Shard)로 분할되고, 각 샤드는 여러 노드에 분산되어 저장된다. 또한, 리플리카 샤드가 다른 노드에 복제되어 데이터의 고가용성을 보장한다.
- 인덱싱: Elasticsearch에서 데이터를 인덱싱하면, Elasticsearch는 이 데이터를 Lucene의 역인덱스 형식으로 변환하여 저장한다.
- 검색: Elasticsearch는 사용자가 보낸 검색 쿼리를 여러 노드에 분산시켜 검색을 수행하고, 그 결과를 합쳐서 사용자에게 반환한다.
Elasticsearch 와 Lucene 의 상호 동작 흐름
- 데이터 인덱싱:
- Lucene 이 데이터를 역색인하여 단일 노드에 저장한다.
- Elasticsearch 는 데이터를 여러 샤드로 나누어서 여러 노드에 저장하고, 각 샤드는 내부적으로 Lucene 역색인을 사용해서 데이터를 저장한다.
- 쿼리 처리:
- Lucene 은 쿼리를 처리할 때 단일 노드에서 역색인을 검색해서 일치하는 문서를 변환한다.
- Elasticsearch는 쿼리를 여러 노드에 분배하여 병렬로 검색을 진행한 뒤, 각 노드의 결과를 통합해서 최종 결과를 반환한다.
- 확장성 / 고가용성
- Lucene은 단일 노드라 확장성과 고가용성이 제한된다.
- ElasticSearch는 데이터를 샤드로 분할하고, 여러 노드에 분산 저장해서 수평적 확장성을 제공한다. 그리고 리플리카를 통해 복제 샤드를 여러 노드에 분산해두기 때문에, 고가용성을 보장하고 장애 발생 시 자동 복구도 가능하다.
- 결론
- Lucene 은 검색 및 인덱싱을 위한 저수준 라이브러리로 단일 노드에서 동작함.
- Elasticsearch 는 Lucene을 기반으로 분산 시스템 기능과 대규모 데이터 처리 및 고속 검색을 지원한다.
그럼 이제 이 단일 노드를 넘어, 여러 노드가 모인 하나의 Elasticsearch 클러스터를 보자.
Elaticsearch 클러스터
- 인덱스: 문서의 집합. DB Table 같은 개념.
- 샤드: 인덱스는 그 내용을 여러 샤드로 분산해서 저장한다. 그리고 고가용성을 위해 1개 주샤드에 N개 복제샤드를 구성하여 복제한다.
- 노드: N개의 샤드가 모이면 하나의 노드가 된다. 엘라스틱서치는 고가용성을 제공하기 위해 같은 종류의 샤드를 다른 노드에 배치한다. 즉, 0번 샤드의 주 샤드와 복제 샤드가 있을 텐데, 이 둘을 같은 노드에 배치하지 않고, 0번 샤드의 복제본이 두개라면 이 둘도 서로 다른 노드로 배치한다.
- 데이터 노드 : 샤드를 보유하고 샤드에 실제로 읽기 / 쓰기 작업을 수행한다.
- 마스터 노드 : 클러스터를 관리하는 역할. 인덱스 생성이나 삭제, 어떤 샤드를 어느 노드에 할당할 것인지 결정한다. 따라서 데이터를 저장하지는 않는다.
- ingest 노드 : 데이터가 색인되기 전에 전처리를 수행하는 노드.
- 클러스터: 엘라스틱서치 노드 여러개가 모여 하나의 클러스터를 구성한다.
노드 지정 예시
node.master: true # 이 노드를 마스터 노드로 지정
node.data: false # 이 노드는 데이터를 저장하지 않음
node.ingest: false # 이 노드는 데이터를 처리하지 않음
cluster.name: my-cluster
node.name: node-1
network.host: 192.168.1.10
데이터의 검색과 저장 흐름
다시 상세로 돌아가서, Elasticsearch에서 데이터가 디스크에 어떻게 저장되고 검색되는지 보자.
세그먼트
- Lucene
- Lucene의 인덱스 구조에서 가장 기본적인 데이터 저장 단위. immutable 하기 때문에 데이터가 인덱스에 추가될 때마다 새로운 세그먼트가 생성되고 기존 문서가 삭제되면 삭제 플래그만 표시해둔다. 업데이트가 되면 삭제 플래그 표시 후 새 세그먼트를 생성한다.
- 세그먼트가 불변이기 때문에 무작정 늘어나면 데이터 저장 공간이 부족하다. 따라서 루씬이 적당히 세그먼트의 병합을 수행해서 디스크 공간을 효율화한다.
- Elasticsearch
- 각 샤드가 독립적으로 세그먼트를 관리하고 자기만의 세그먼트를 갖고 있다. (각 샤드 = 루씬 동작 범위..)
인메모리 버퍼
- Lucene
- 인메모리 버퍼는 문서가 디스크로 flush 되기 전에 메모리 상에서 임시로 저장되는 공간이다. 이 버퍼에 문서들이 쌓이다가 일정량이 되면 디스크로 플러시 되면서 새로운 세그먼트가 생성된다.
- 버퍼가 일정 용량에 도달하면 해당 데이터를 세그먼트로 플러시 해서 디스크에 영구적으로 저장한다.
- 자동 플러시가 주기적으로 이뤄진다.
- Elasticsearch
- 인메모리 버퍼도 각 샤드별로 관리하고, 주기적으로 데이터를 디스크로 플러시한다.
플러시 (Flush)
- 인메모리버퍼에 있는 데이터를 디스크에 저장하는 과정이고, 이를 통해 세그먼트가 디스크에 생긴다.
- 데이터가 메모리에만 존재하면 장애 발생 시 손실될 수 있고, 플러시 과정을 거친 뒤에야 디스크에 영구 저장된다.
- 플러시가 발생하면 세그먼트 생성과 함께 디스크에 쓰여지고, 이후 해당 문서는 검색 가능한 상태로 변환된다. 그러나 즉시 반영이 되지는 않는다. 커밋이 되어야만 쿼리에 반영이 되고 플러시만 된 상태에서는 검색할 수 없다.
커밋 (Commit)
- Flush 이후 디스크에 기록된 데이터를 최종적으로 검색 가능한 상태로, 즉 실제로 확인 가능한 상태로 만드는 작업이다. 플러시 후 커밋이 되면 해당 데이터는 검색 쿼리에서 사용할 수 있도록 보장된다.
- 커밋은 쓰기 작업의 안전성을 보장한다. 장애가 발생하면 마지막 커밋 이후의 데이터를 복구할 수 있도록 한다.
Elasticsearch 의 refersh와 Lucene 에서의 동작
Elasticsearch에서 refersh 는 검색 가능한 상태로 만들기 위한 작업을 의미한다. 즉, 새로 인덱싱된 문서나 수정된 문서가 검색에 반영되도록 하는 중요한 작업이다. Elasticsearch 는 주기적으로 refesh 를 수행하는데, 디폴트는 1초이고, 이 주기는 index.refersh_interval 을 통해 조절할 수 있다. 실시간을 요구하는게 아니라면 좀 늘리는게 성능 상 좋다.
그럼 elasticsearch에서 refresh가 일어날 때 어떻게 동작이 될까?
- 문서 인덱싱
- 새 문서가 인덱싱 되면 Elasticsearch는 메모리 버퍼에 데이터를 저장한다.
- 이 시점에는 문서가 검색되지 않는다.
- Flush
- 일정 주기 후, 또는 수동 flush 하면, 메모리 버퍼의 데이터가 디스크로 기록된다.
- Lucene 은 새 세그먼트를 검색 인덱스에 포함시켜, 새로 추가된 데이터를 검색 가능 상태로 만든다.
- 인덱싱된 새 문서는 검색 쿼리에 포함되어 반영된다.
이미지 자료
https://stackoverflow.com/questions/47003336/elasticsearch-index-sharding-explanation
https://blog.expertrec.com/elasticsearch-vs-lucene-understanding-the-differences/
'Tech > DB' 카테고리의 다른 글
RDB Query Plan 확인 (+ Vitess Query Plan) (0) | 2024.11.24 |
---|---|
Vitess 용어 (2) | 2024.10.27 |
MongoDB 쿼리 플랜 (간단하게!) (0) | 2024.03.29 |
DB Index (RDBMS) (4) | 2024.03.01 |