[검색엔진 라이브서치 개발과정 정리]ElasticSearch의 개요

2019. 5. 16. 14:51ELK stack

1.     Elasticsearch 의 개요

 

Elasticsearch(이하 ES)는 아파치 루쉰 기반의 검색엔진으로 2010년에 개발되었다. Full-text에 대해 실시간 분산 검색/분석 기능을 제공하며, RESTful 인터페이스를 제공한다. 그러나 실제로는 Near Realtime으로 문서를 색인화 하는 시점부터 검색이 가능해지는 시점은 약간의 대기시간(대개 1)이 있다.

Java로 개발되었으며, 내부적으로 main()메소드를 통해 구동이 된다. 따라서 JVM위에서 작동하기 때문에 jdk1.8 이상의 환경을 필요로 한다. 이러한 부분 때문에 다양한 플랫폼에서도 구동하기가 수월하다.

 

ES의 기본적인 기능은 이러하다.

 

1.     ES는 정형, 비정형 데이터에 대하여 페타 바이트급까지 스케일 업이 가능하다.

2.     ES MongoDB, RavenDB와 같이 document 기반의 store를 대체하여 사용할 수 있다.

3.     ES는 조회 성능을 향상시키기 위해 비정규형(denormalization)모델을 사용한다.

4.     ES는 매우 큰 규모의 엔터프라이즈에서 사용되고 있는 엔진이다(위키피디아, 스택오버플로우, 깃허브 등)

 

ES main()메소드로 실행이 될 때, ES의 설정이나 노드 인스턴스의 생성 후, HttpServer.java 라는 클래스를 실행한다. 이것은 Netty라는 구현체를 사용하는데, 이 구현체는 Java 환경으로 구현된 비동기 이벤트 드리븐 네트워크 어플리케이션 프레임워크이다. 프로토콜 서버 및 클라이언트 같은 네트워크 어플리케이션의 개발을 위한 NIO 클라이언트 서버 프레임워크이며, TCP 또는 UDP 소켓 서버와 같은 네트워크 프로그래밍을 간단하게 활용할 수 있도록 한다.

 

, ES는 이러한 방법을 통해 RESTful 형태의 http 통신을 활용하여 독립적으로 검색엔진으로서 기능할 수 있다.

 

ES는 동작하는 과정에서 Node라는 인스턴스를 생성한다. ES는 기본적으로 JSON 타입의 데이터 형태로 text를 저장하고 분석하는데 이러한 과정이 이뤄지는 것은 모두 Node를 통해 일어난다.

 

그렇다면 ES에서의 Node는 무엇일까?

 

ES는 기본적으로 분산검색이 가능하다. 분산 검색이 가능하다는 것은 데이터에 대해 분산처리가 가능하다는 것이다. 그리고 Node와 클러스터가 바로 이러한 분산처리가 가능하게 하는 ES의 구조이다. , Node ES라는 Java 어플리케이션의 인스턴스이자, 서버이다.

 

Node ES의 인스턴스이며, 자신만의 이름을 갖는다. Node는 가동할 때 자신의 UID를 갖는다. , JVM 에서 자신만의 프로세스를 갖는 것이 바로 Node라고 할 수 있다. 이것은 다수의 shard로 구성되며, 역할에 따라 마스터, 데이터, 인제스트, 트라이브 Node로 구분된다.

 

Master Node는 인덱스의 생성, 삭제. 클러스터의 Node에 대한 추적, 관리, 데이터 입력 시 어느 shard에 할당할지를 결정한다. 따라서 master node를 안정적으로 관리하는 것이 전체 cluster의 상태를 안정적으로 관리할 수 있는 중요한 요소가 된다. Master node의 경우 CPU, 메모리, I/O 리소스 소모가 클 수 있기 때문에 master data node를 구분해서 운영하는 것이 권장된다.

 

그렇다면 클러스터는 무엇인가? 클러스터는 다수의 Node로 구성된 단위라고 볼 수 있다. 클러스터는 ES 시스템의 가장 큰 단위이다. 클러스터는 고유한 이름으로 식별되는데, Node가 클러스터에 포함되기 위해서는 이름에 의해 클러스터의 구성원이 되도록 설정되기 때문에 이름을 정하는 것은 중요하다. 따라서 동일한 클러스터 이름을 서로 다른 환경에서 재사용하는 것을 주의해야한다. 때로는 클러스터에 하나의 Node만 존재할 수 있다.

 

아래의 사진은 ES의 클러스터, 노드, 샤드가 어떤식으로 구성되어 있는지를 보여준다.

 

 

인덱싱 과정에서 데이터는 노드에 의해 여러 샤드로 복제된다. 일반적으로 한 개의 샤드에는 1TB까지의 데이터 제한을 두고, 노드의 유실이나 샤드의 문제 때문에 데이터와 기능에 문제가 되지 않도록 기본 샤드에 대한 데이터가 복제되어 있다. 따라서 기본적으로 기능 제공에 대해 높은 안정성을 지니고 있다. 그러나 너무 많은 복제샤드는 인덱싱 시간의 증가와 성능의 하락을 만들 수도 있다. 따라서 각자의 이용목적/규모에 맞는 설정이 필요하다.

 

ES는 색인/매핑/객체 작업의 안정성을 보장하기 위해 내부적으로 작업을 실행하는 방법에 관한 엄격한 규칙을 갖고 있다. ES의 작업은 다음과 같이 구분할 수 있다.

 

l  클러스터/색인 작업: 모든 쓰기 작업은 잠긴 상태며, 먼저 마스터 노드에 반영하면 보조 노드에 반영한다. 읽기 작업은 보통 모든 노드에 전달된다.

 

l  도큐먼트 작업: 모든 쓰기 작업은 조회 샤드에서만 잠긴다. 읽기 작업은 모든 샤드 레플리카에 전달된다.

ES는 데이터를 저장할 때 다음에 의해 목적 샤드를 선택한다.

 

l  레코드(document, JSON 객체)의 고유 식별자(ID). ID가 없다면 ES가 자동으로 임의의 ID를 생성한다.

 

l  routing이나 parent 파라미터를 지정했다면 이들 파라미터 해시 값으로 적합한 샤드를 선택한다.

 

ES는 가용한 모든 노드에 샤드 분포의 균형을 맞추려 노력한다. 따라서 샤드를 인덱싱 분할하여 여러 노드에 데이터를 저장한다. 모든 샤드는 대략 49억건까지 포함할 수 있으므로 저장 공간이 실제 샤드 크기의 제약이 된다. 샤드가 데이터를 갖고 있기 때문에 검색 과정에서 계산하고 결과를 조회할 때 샤드를 사용한다. 그래서 대규모 데이터에서 ES 성능은 샤드 개수에 따라 수평적으로 확장된다. 모든 네이티브 레코드 작업(인덱싱, 검색, 업데이트, 삭제)은 샤드가 관리한다.

 

인덱스는 한 개 이상의 레플리카를 가질 수 있다. 기본 레플리카의 일부분이면 기본샤드(primary shard)로 부르고, 그 외 레플리카의 일부분이면 보조(secondary)로 부른다. 쓰기 작업의 일관성 유지를 위해 다음의 작업 절차를 실행한다.

 

l  쓰기 작업은 기본 샤드에서 먼저 실행한다.

 

l  기본 샤드에 쓰기가 성공하면 모든 보조 샤드로 쓰기가 동시에 전파된다.

 

l  기본 샤드를 사용할 수 없게 되면 보조 샤드가 기본 샤드로 선출(가능하다면)되고, 이 절차를 다시 실행한다.

 

최소한 한 개의 레플리카를 확보하는 것이 노드 실패에서도 다운타임과 데이터 손실 없이 서비스를 유지할 수 있다.

ES의 데이터는 기본적으로 JSON 형태로 이뤄진다. Full-text 검색이기 때문에, JSON key : value 구조를 그대로 활용한다. 또한 ES Http 통신을 통해 REST 형태로 데이터를 주고받는다.

기본적인 통신문법은

http://<ES주소>/<index>/<Doc_type>/<REST>

형태를 지닌다. 웹서비스로 접근시에는 9200포트를 활용하도록 되어있으며, 네이티브 ES 프로토콜의 경우 9300포트로 설정되어 있다.