오늘은 리눅스에 대한 이야기 말고 애플리케이션과 관련된 이야기를 해볼까 합니다.
그 중에서도 ElasticSearhch (이하 ES)에 대한 이야기를 해보려고 합니다. 개인적으로 업무 상 필요에 의해서 진행한 내용을 정리도 할겸, 글을 써 봤습니다.
그럼 시작 합니다~
새로운 서비스들이 런칭되면서 검색 기능을 붙이고 싶어하는 경우가 간혹 있습니다. 그리고 최대한 간단하게 그리고 빠르고 안정적으로 검색 기능을 붙이는 데에 ES 만한 솔루션이 없습니다. ^^ 하지만 신규 서비스 인데다가, 아직 트래픽이 많지 않기 때문에 아주 간단하게 구성을 하게 되죠. 그래도 서비스에 투입해야 하니 이중화를 위해 최소 2대 이상으로 구성되게 됩니다. 이렇게 구성된 ES들은 트래픽이나 사용률이 높지 않기 때문에 개별 서버의 입장에서 봤을 때는 사용하는 리소스가 그리 크지 않습니다. 그리고 이런 식으로 신규 서비스마다 ES를 구축하게 되면 전체적인 시스템의 리소스가 낭비 되는 현상이 발생하죠. 그래서
ES를 Farm처럼 구성해서 신규 서비스들에게 할당해 준다면 시스템 리소스의 낭비도 막고, 설치 및 구성하는데 소요되는 개발자들의 시간도 절약해 줄 수 있지 않을까
해서 시작해 봤습니다.
기본 컨셉은 아래와 같습니다.
1. ES를 대표하는 9200 포트는 nginx에서 받아 줍니다.
2. 뒷 단에는 서비스 별로 독립적인 ES 인스턴스를 실행 시킵니다. 이 때의 포트는 920X 가 됩니다.
3. nginx는 server_name (아파치의 virtualhost와 같은 기능) 지시자를 이용해서 서비스 별 ES로의 트래픽을 분기 해 줍니다.
이런 방식의 서버를 N대로 구성해서 로드 밸런서에 붙이면 위와 같은 그림이 됩니다. 그리고 각각의 서비스 마다 도메인을 설정해서 nginx에서 분기 시키도록 합니다. 이렇게 되면 논리적으로 분리된 각각의 ES 인스턴스로 요청이 전달 되고 Farm 의 형태이지만 독립적인 운영과 관리가 가능해 집니다.
그럼 설정 파일을 조금 더 살펴 보겠습니다. 우선 nginx는 아래와 같이 설정 합니다. nginx.conf 파일의 내용 입니다.
http {
include mime.types;
default_type application/octet-stream;
... (중략) ...
include ./es/*.conf;
}
ES 관련된 개별 설정은 conf/es 디렉터리를 만들어서 각각의 파일로 관리해 줍니다. 파일 내용은 아래와 같이 설정 합니다.
upstream infra-es {
server 127.0.0.1:9201;
keepalive 64;
}
server {
listen 9200;
server_name infra-es-dev.domain.com;
access_log logs/infra-es-dev.access.log main;
location / {
proxy_pass http://infra-es;
proxy_http_version 1.1;
proxy_set_header Connection "Keep-Alive";
proxy_set_header Proxy-Connection "Keep-Alive";
}
}
upstream 지시자는 각 서비스에서 사용하게 될 ES 인스턴스를 가리키게 됩니다. 여기서는 9201 포트를 사용하는 ES 인스턴스가 됩니다. 그리고 server_name은 서비스에서 접근할 때 사용하게 될 도메인 명을 기입해 줍니다.
여기에 새로운 서비스가 추가 된다면 새로운 ES 인스턴스를 9202 포트로 띄워 주고, upstream 설정을 수정한 conf 파일을 하나 더 만들어서 nginx를 reload 해 주면 됩니다.
주의해야 할 부분은 server 지시자에 있는 listen 항목 입니다. 항상 9200을 유지해 주어야 도메인 기반으로 요청을 분기 할 수 있습니다.
그렇다면 ES는 어떻게 설정할까요?
필요할 때 마다 elasticsearch.zip 파일의 압축을 풀어 주고, 압축을 푼 디렉터리의 이름을 서비스명으로 바꿔준 후 config 파일을 수정해 줍니다. 세부적인 과정은 아래와 같습니다.
1. elasticsearch-2.1.1.zip 을 다운로드 받아서 압축을 해제합니다.
2. 예를 들어 infra 에서 사용할 용도로 ES Farm을 만든다면, elasticsearch-2.1.1.zip 압축을 푼 후 infra-es 라고 디렉터리 이름을 바꿔 줍니다.
3. 새로 풀어준 infra-es의 config/elasticsearch.yml 파일을 수정한다.
그리고 그 때 사용하는 config 파일은 아래와 같습니다.
cluster.name: infra-dev
node.name: infra-es-dev01
path.data: /data/infra-es/data
path.logs: /data/infra-es/log
network.host: 0.0.0.0
http.port: 9201
discovery.zen.ping.unicast.hosts: ["클러스터 IP"]
cluster.name은 서비스 별로 적당한 이름으로 생성해 주면 됩니다. path.data, path.logs 가 서비스 별로 독립적으로 구성되기 때문에 서로의 인덱스 명이 겹치거나 하는 이슈도 없습니다. 그리고 제일 중요한 http.port는 다른 서비스를 위해 구성해 둔 ES 인스턴스와 겹치지 않게 항상 새로운 포트 번호를 할당해 줍니다.
위와 같은 방식으로 ES Farm이 완성이 되면 개발자들은 더이상 ES의 설치 및 구성, 이중화, 용량 관리 등의 업무를 하지 않아도 됩니다. 그저 도메인을 할당 받아서 사용하기만 하면 됩니다. 마치 API를 사용하듯이 ES 클라이언트를 통해서 infra-es-dev.domain.com:9200 으로 원하는 작업을 하기만 하면 됩니다.
이를 통해 좀 더 개발 업무 본연에 집중 할 수 있게 되며, 인프라를 구성하는 시스템 엔지니어의 입장에서는 좀 더 안정적인 서비스를 구성할 수 있게 됩니다.
여기서 언급된 방법이 ES Farm을 구축하기 위한 최선의 방법은 아닐 겁니다. 구성 방법 중에 하나라고 생각 합니다. 관련해서 더 좋은 정보들이 있으면 함께 공유 하면 좋을 것 같습니다.