Elastic Search 에서 document를 대량으로 insert 하는 방법

 

 

from elasticsearch import Elasticsearch
from elasticsearch import helpers

#  ES 연결 
es = Elasticsearch([{'host': '192.168.xx.xxx', 'port': 9905}])

docs = [[123, 'aa', 'bb', 'cc'],
        [456, 'AA', 'BB', 'CC']]

for cnt in range(2):
    docs.append({
        '_index': 'id_and_values_index',
        '_type': '_doc',
        '_source': {
            'm_val': docs[cnt][0],
            'time': docs[cnt][1],
            'up_time': docs[cnt][2],
            'm_id': docs[cnt][3],
        }
    })

helpers.bulk(es, docs)
728x90

엘라스틱서치를 이해하기 위해 필요한 개념

 

(도서) 엘라스틱서치 실무 가이드의 9장 '엘라스틱서치와 루씬'을 읽고 내용을 간추렸다. 

http://www.yes24.com/Product/Goods/71893929

 

 

  • 클러스터

클러스터 데이터를 실제로 가지고 있는 하나 이상의 노드들로 구성된다. 연관된 노드들끼리는 하나의 클러스터의 구성원으로 연결되어야 한다. 같은 클러스터 내부의 노드들끼리만 데이터를 공유할 수 있기 때문이다. 

 

  • 노드

물리적으로 실행된 런타임 상태의 엘라스틱서치를 노드라고 한다. 

엘라스틱서치 클러스터를 운영하기 위해 하나 또는 다수의 물리 서버에 엘라스틱서치를 설치하고 실행하게 된다. 

 

  • 노드의 종류

1) 마스터노드 : 클러스터의 제어를 맡는다. 노드들의 상태를 모니터링. 색인 요청에 대한 데이터의 라우팅. 장애 발생 시 레플리카를 이용하여 샤드를 복구하는 책임을 가진다.
2) 데이터노드 : 데이터를 보유, CRUD, 검색, 집계한다. 
3) 인제스트 노드 : 색인 전 "전처리" 작업을 담당한다. 데이터 변환 등 사전 파이프라인 처리를 한다.  
4) 코디네이팅 노드 : 검색이나 집계 시 "분산 처리"만을 목적으로 설정된 노드다. 
5) 트라이브 노드 : cross cluster search(여러 클러스터에 접근하여 동시에 검색)를 제공하는 특수한 목적의 노드이다. 최신 버전에서는 폐기 예정이다.

 

  • 인덱스 

유사한 특성을 가지고 있는 문서를 모아놓은 문서들의 컬렉션. RDBMS에서 테이블의 개념과 유사하다.
유의할 점 하나는 인덱스명은 반드시 소문자여야 한다.
하나의 인덱스에는 하나의 타입만 생성해야 한다.

인덱스에 Document문서(RDBMS에서 하나의 row와 같다)들이 저장되는데, 이것들이 물리적으로 분산 저장되는 곳이 샤드이다. 

 

  • 샤드

샤드는 인덱스의 전체 데이터를 분산해서 가지고 있는 일종의 부분집합이다. 
샤드로 인해 데이터를 분산 저장하는 방식으로 손쉬운 수평 확장이 가능해진다. (엘라스틱서치의 고가용성이 구현됨)
인덱스를 생성할 때, 엘라스틱서치는 기본적으로 5개의 샤드로 데이터가 분산되도록 생성되지만 개수는 변경이 가능하다.
색인 데이터가 샤드로 분산되는 과정이나 검색 요청이 각 샤드에 분산되어 처리되는 프로세스는 사용자에게는 블랙박스로 제공된다.

 

  • 레플리카

샤드의 복제본. (레플리카는 서로 다른 노드에 존재할 것을 권장한다. )
검색 시 레플리카가 적극적으로 활용된다.

인덱스가 생성될 때 샤드 개수와 레플리카 개수를 설정할 수 있지만, 인덱스 생성 후에는 샤드 개수 변경이 불가하다.
그래서 샤드 개수 설정은 매우 신중히 결정해야한다. 
그에 반해 레플리카 개수는 인덱스 생성 후에도 변경 가능하다.
그래서 운영 중 트래픽 증가에 유연한 대응이 가능하다.

 

  • 세그먼트

문서들은 빠른 검색에 유리하도록 '역색인 구조'(inverted index)로 저장된다.
책 맨뒤에 키워드 마다 찾아볼 수 있도록 '찾아보기'가 inverted index이다. 
(책의 맨 앞의 목차가 index이다. )
샤드 내부에 루씬 라이브러리가 있는데, 이를 이용해 검색 기능이 구현된다.
루씬에 데이터가 색인되면, 데이터는 최소한의 단위인 토큰으로 분리되고, 결국 세그먼트 라는 자료구조로 저장된다.
세그먼트는 '역색인 구조'로 생성되어 있어서 읽기에 최적화된 자료구조이므로 검색 성능에 좋다. 

 

  • 루씬 인덱스

루씬은 다수의 클래스로 구성돼 있는 검색 라이브러리이다. 
핵심 클래스 두 가지는 데이터를 색인하여 세그먼트를 생성하는 IndexWriter와 
색인된 데이터(세그먼트)를 검색하는 IndexSearcher이다.
위의 두 클래스를 가지고 색인과 검색을 동시에 제공하는 루씬 인스턴스를 루씬 인덱스라고 한다.
하나의 샤드는 하나의 루씬 인덱스이다.
물리적으로 분산된 엘라스틱서치 샤드를 논리적 관점에서 하나의 거대한 데이터로 바라보는 것이 엘라스틱서치 인덱스이다. 

 

  • Near Real Time 검색 (근실시간 검색)

커밋포인트 : 여러 세그먼트의 목록 정보를 가지고 있으며, 검색 요청 시 활용된다.
루씬의 IndexSearcher 가 검색 요청 시 커밋 포인트를 이용해 가장 오래된 세그먼트부터 차례로 검색하여 결과를 낸다.
세그먼트가 많아지면 읽기 성능이 떨어지므로, 루씬이 백그라운드로 주기적으로 세그먼트 파일을 병합한다.

 

  • 세그먼트의 불변성 (Immutablity)

세그먼트의 수정을 허용하지 않은 동작 방식을 불변성(Immutablity) 라고 부른다.
역색인 구조로 생성된 세그먼트라는 특징 때문에, 불변성은 장점이 많은 방식이다. 


1) 동시성 문제를 회피할 수 있다.  
다중 스레드 환경에서 lock이 필요 없어진다. (수정이 가능하면 lock이 필요하기 때문) 
2) 시스템 캐시를 적극적으로 활용할 수 있다.
불변성을 보장하지 않을 경우, 데이터가 변경될 때마다 시스템 캐시를 삭제하고 다시 생성해야 하는데, 이는 성능 측면에서 매우 비용이 큰 작업이다.
3) 높은 캐시 적중률.
검색 시 데이터를 항상 메모리에서 읽어올 수 있다.

읽기 연산이 대다수인 검색엔진의 특성상 캐시 성능을 최대한 활용할 수 있다는 장점이 불변성을 채택하는 이유가 된다. 
불변성의 단점은 일부 데이터가 변경된다면 전체 역색인 구조가 다시 만들어져야 한다는 것이다. 

또한 실시간 반영이 어렵다.
변경이 일어날 때마다 세그먼트를 다시 만들지 않고, 추가로 세그먼트를 생성하는 것으로 이러한 단점을 극복한다.
그 이후, 생성된 모든 세그먼트를 읽어서 검색 결과를 제공한다. 

 

  • 루씬을 위한 Flush, Commit, Merge

루씬은 효율적인 색인 작업을 위해 내부적으로 일정 크기의 버퍼를 가지고 있다.
이러한 내부 버퍼를 인메모리버퍼 라고 한다.
버퍼가 없다면, 대량의 데이터가 빠르게 요청될 경우 지연이 발생하여 서비스 장애로 이어질 수 있다.
버퍼를 일종의 큐 처럼 활용한다. 
write()함수를 이용해 커널의 시스템 캐시에 기록하는 쓰기 과정을 수행하고, 일정한 주기에 따라 물리적 디스크 동기화 작업(commit)을 수행한다. 
이러한 인메모리 버퍼 기반의 처리과정을 루씬에서는 Flush 라고 부른다. 
루씬에서는 물리적으로 디스크에 기록을 수행하는 fsync() 함수를 호출하는 작업을 Commit이라고한다. 

루씬은 불변성을 유지하기 위해 세그먼트 단위 검색을 제공하지만,
시간이 흐를수록 세그먼트들의 개수가 늘어나고, 이를 위해 커밋 포인트의 부하도 증가한다.
그래서 다수의 세그먼트를 하나로 합치는 작업이 필요해진다. 
이를 Merge 작업이라고 한다. 
Merge 작업으로 인해 세그먼트 개수가 줄어들면 검색 횟수가 줄어들어 검색 성능이 좋아진다. 
하지만 Merge 작업은 세그먼트를 합치면서 데이터를 삭제하므로,
commit작업을 반드시 동반해야 하므로 매우 비용이 많이 든다. 적절한 주기 설정이 필요하다. 

 

  • 엘라스틱서치를 위한 Refresh, Flush, Optimize API

엘라스틱서치 샤드는 내부에 루씬 인덱스를 가지고 있고, 루씬 인덱스가 가지는 대부분의 기능을 확장해서 API로 제공한다. 

루씬 엘라스틱서치
Flush  Refresh 
Commit  Flush 
Merge  Optimize API 


Refresh : 클러스터에 존재하는 모든 샤드에서 기본적으로 1초마다 한번씩 Refresh 작업이 수행된다.
인덱스를 새로고침해서 새로 추가한 데이터의 검색이 가능해지게 한다. 
_setting API를 이용하면 Refresh 주기를 변경할 수 있다. 
특별한 경우가 아니면 주기를 변경하지 않는 것이 좋다.

Flush : 루씬의 Commit작업을 수행하고, 새로운 Translog를 시작한다는 의미다. 

Translog는 루씬에는 없는 개념. ES가 제공하는 고가용성과 관련이 있다.
Translog는 샤드의 장애복구를 위해 제공되는 특수한 파일이다. 
ES 샤드는 자신의 모든 변경사항을 Translog에 먼저 기록한 후 내부에 존재하는 루씬을 호출한다. 
지속적인 Refresh 작업에 의해 검색은 가능해지지만 아직은 디스크에 물리적 동기화가 되지 않은 상태이므로 주기적으로 루씬 commit을 수행해야 한다.

정책에 의해 루씬 commit이 정상 수행되면, 변경사항이 디스크에 물리적으로 기록이되고,
Translog 파일에서 commit이 정상적으로 일어난 시점까지의 내역이 비로소 삭제된다.
ES에서 기본적으로 5초에 한번씩 Flush 작업이 수행된다. 

Optimize API: 인덱스 최적화를 위해 Optimize API를 제공한다. 이를 forced merge API라고도 한다. (루씬 Merge를 강제로 수행하는 기능)

 

  • Translog 동작 순서

1)데이터가 추가되면 Translog에 기록되고 동시에 인메모리 버퍼에 추가된다.
2) Refresh가 수행되면 인메모리 버퍼에서는 사라지지만 Translog에는 계속 남아있다.
3) 더 많은 데이터가 추가되고 지속적으로 세그먼트가 추가된다. 
4) Translog가 일정 크기 이상 커지면, Flush 작업이 수행된다.
5) 커밋 포인트가 디스크에 Flush 된다. 
6) 시스템 캐시의 내용이 디스크에 Flush 된다.
7) Translog의 기록이 비로소 삭제 된다. 


참고)
커밋포인트 : 여러 세그먼트의 목록 정보를 가지고 있으며, 검색 요청시 활용된다.
루씬의 IndexSearcher 가 검색 요청 시 커밋 포인트를 이용해 가장 오래된 세그먼트 부터 차례로 검색하여 결과를 낸다.

  • 엘라스틱서치 샤드 최적화

샤드 : 실제 서비스가 일어나는 프라이머리 샤드. 실질적인 CRUD 를 제공한다.
레플리카 샤드 : 장애 복구를 위해 존재하지만, 프라이머리 샤드와 동일한 데이터 가지고 있으므로 평상시에 읽기 분산에 활용된다. 

number_of_shards : 프라이머리 샤드의 개수. 
number_of_replicas : 레플리카 세트를 몇개로 구성할지 설정.

5개의 샤드로 분산하고, 1개의 레플리카 세트를 생성하도록 설정한다고 했을 때,
인덱스가 생성되면 5개의 프라이머리 샤드와 5개의 레플리카 샤드가 생성되어, 인덱스 내에 총 10개의 샤드가 존재한다.

샤드는 내부에 독립적인 루씬 라이브러리를 가지고 있고, 루씬은 단일 머신 위에서만 동작하는(Stand Alone) 검색엔진이다.
프라이머리 샤드의 개수를 변경한다는 뜻은 독립적인 루씬 들이 가지고 있는 데이터들을 모두 재조정 하겠다는 뜻이다. 
각 세그먼트는 원칙적으로 변경이 불가능하므로, 프라이머리 샤드의 개수를 변경할 수는 없다.
이 경우, 새로운 인덱스를 생성하고 재색인 하도록 엘라스틱서치에서는 ReIndex API 를 제공한다. 

프라이머리 샤드와 레플리카 샤드는 동일한 세그먼트 생성 과정을 거치게 된다. 
이러한 과정 덕분에 모든 복제본에 일관성이 부여된다.
읽기 분산이 중요한 경우, 색인 성능을 일부 포기하고 레플리카 세트의 수를 늘리는 것이 좋다.
빠른 색인이 중요한 경우, 읽기 분산을 일부 포기하고 레플리카 세트의 수를 줄이는 것이 좋다.

개별 인덱스를 생성할 때 설정 가능한 샤드의 수는 1024개로 제한되어 있다. 

샤드가 많아질 수록 마스터 노드의 부하가 증가한다.
샤드 하나가 물리적으로 50GB가 넘지 않도록 권장한다. 

 

728x90

+ Recent posts