Hanbit ebook Realtime 59 실무예제로배우는 Elasticsearch 검색엔진기본편 정호욱지음
실무예제로배우는 Elasticsearch 검색엔진 기본편
실무예제로배우는 Elasticsearch 검색엔진기본편 초판발행 2014 년 3 월 25 일 지은이정호욱 / 펴낸이김태헌펴낸곳한빛미디어 ( 주 ) / 주소서울시마포구양화로 7길 83 한빛미디어 ( 주 ) IT출판부전화 02-325-5544 / 팩스 02-336-7124 등록 1999년 6월 24일제10-1779호 ISBN 978-89-6848-691-3 15000 / 정가 11,000원 책임편집배용석 / 기획 편집정지연디자인표지여동일, 내지스튜디오 [ 밈 ], 조판최송실영업김형진, 김진불, 조유미 / 마케팅박상용, 서은옥, 김옥현 이책에대한의견이나오탈자및잘못된내용에대한수정정보는한빛미디어 ( 주 ) 의홈페이지나아래이메일로알려주십시오. 한빛미디어홈페이지 www.hanbit.co.kr / 이메일 ask@hanbit.co.kr Published by HANBIT Media, Inc. Printed in Korea Copyright c 2014 정호욱 & HANBIT Media, Inc. 이책의저작권은정호욱과한빛미디어 ( 주 ) 에있습니다. 저작권법에의해보호를받는저작물이므로무단복제및무단전재를금합니다. 지금하지않으면할수없는일이있습니다. 책으로펴내고싶은아이디어나원고를메일 (ebookwriter@hanbit.co.kr) 로보내주세요. 한빛미디어 ( 주 ) 는여러분의소중한경험과지식을기다리고있습니다.
저자소개 지은이 _ 정호욱지난 13년동안야후코리아, NHN Technology, 삼성전자에서커뮤니티, 소셜검색, 광고검색관련서비스를개발해오면서검색엔진을활용한다양한프로젝트를수행하였다. 현재빅데이터전문기업인그루터 Gruter 에서오픈소스기반검색엔진개발자로근무하고있다. elasticsearch 기술에대한정보와경험을현재개인블로그 (http://jjeong.tistory.com) 를통해공유하고있다.
저자서문 검색엔진은모든서비스의기본이되는핵심요소입니다. 우리가사용하는모든서비스에는검색기능이포함되어있습니다. 하지만검색엔진관련기술은일반사용자가접근하기에는너무어려운기술로남아있습니다. 루씬 Lucene 이라는오픈소스검색라이브러리가진입장벽을많이낮추기는했지만, 서비스에적용하기에는개발자가직접구현해야하는기능이너무많고관리와유지보수가어렵다는문제가있었습니다. 하지만이런문제점은 elasticsearch 라는오픈소스검색엔진이나오면서사라졌 고전문적인검색엔진및서비스개발자가아니더라도누구나쉽게검색서비스를 만들수있게되었습니다. 비싼라이선스비용을내고검색품질과기능을커스터마이징하기어려운벤더중심의검색엔진을사용하고있다면 elasticsearch로꼭바꾸길추천합니다. 아직국내에는 elasticsearch 사용자층이높지않습니다. 이책은 elasticsearch에관심은있으나어디서부터시작해야할지모르는사용자와검색을모르는사용자가쉽게서비스를만들수있도록도움을주고자집필하였습니다. 끝으로이책을집필하는데많은도움을주신그루터권영길대표님그리고이책 이세상에빛을볼수있도록많은도움을주신한빛미디어김창수님, 정지연님, 이중민님께감사의말을전합니다. 집필을마치며 저자정호욱
대상독자및참고사항 초급초중급중급중고급고급 이책은 elasticsearch 1.0.0 을이용해서검색엔진을구축하고색인, 검색기능을 구현하는방법을소개하는책입니다. 기본예제는일반쇼핑몰상품검색기능을 구현할수있는수준으로작성되어있습니다. Eclipse 로 Maven 프로젝트를생성하여 JUnit 기반의테스트코드를작성해본개 발자라면누구나쉽게읽을수있습니다. 또한, 실무중심으로예제를구성하였으 므로이를검색서비스개발에응용할수있습니다. 이책의검색엔진설치와예제코드실행을위해서는 linux 계열의 OS 와 Java 6 이상이설치된개발환경이갖춰져있어야합니다. 이책의예제코드와프로젝트는아래링크에서받을수있습니다. https://github.com/howookjeong/hanb-elasticsearch-beginner
한빛 ebook 리얼타임 한빛 ebook 리얼타임은 IT 개발자를위한 ebook 입니다. 요즘 IT 업계에는하루가멀다하고수많은기술이나타나고사라져갑니다. 인터넷을아무리뒤져도조금이나마정리된정보를찾는것도쉽지않습니다. 또한잘정리되어책으로나오기까지는오랜시간이걸립니다. 어떻게하면조금이라도더유용한정보를빠르게얻을수있을까요? 어떻게하면남보다조금더빨리경험하고습득한지식을공유하고발전시켜나갈수있을까요? 세상에는수많은종이책이있습니다. 그리고그종이책을그대로옮긴전자책도많습니다. 전자책에는전자책에적합한콘텐츠와전자책의특성을살린형식이있다고생각합니다. 한빛이지금생각하고추구하는, 개발자를위한리얼타임전자책은이렇습니다. 1. ebook Only - 빠르게변화하는 IT 기술에대해핵심적인정보를신속하게제공합니다. 500페이지가까운분량의잘정리된도서 ( 종이책 ) 가아니라, 핵심적인내용을빠르게전달하기위해조금은거칠지만 100페이지내외의전자책전용으로개발한서비스입니다. 독자에게는새로운정보를빨리얻을수있는기회가되고, 자신이먼저경험한지식과정보를책으로펴내고싶지만너무바빠서엄두를못내는선배, 전문가, 고수분에게는보다쉽게집필할수있는기회가될수있으리라생각합니다. 또한새로운정보와지식을빠르게전달하기위해 O'Reilly의전자책번역서비스도하고있습니다. 2. 무료로업데이트되는, 전자책전용서비스입니다. 종이책으로는기술의변화속도를따라잡기가쉽지않습니다. 책이일정분량이상으로집필되고정리되어나오는동안기술은이미변해있습니다. 전자책으로출간된이후에도버전업을통해중요한기술적변화가있거나저자 ( 역자 ) 와독자가소통하면서보완하여발전된노하우가정리되면구매하신분께무료로업데이트해드립니다.
3. 독자의편의를위해 DRM-Free로제공합니다. 구매한전자책을다양한 IT 기기에서자유롭게활용할수있도록 DRM-Free PDF 포맷으로제공합니다. 이는독자여러분과한빛이생각하고추구하는전자책을만들어나가기위해독자여러분이언제어디서어떤기기를사용하더라도편리하게전자책을볼수있도록하기위함입니다. 4. 전자책환경을고려한최적의형태와디자인에담고자노력했습니다. 종이책을그대로옮겨놓아가독성이떨어지고읽기힘든전자책이아니라, 전자책의환경에가능한한최적화하여쾌적한경험을드리고자합니다. 링크등의기능을적극적으로이용할수있음은물론이고글자크기나행간, 여백등을전자책에가장최적화된형태로새롭게디자인하였습니다. 앞으로도독자여러분의충고에귀기울이며지속해서발전시켜나가도록하겠습니다. 지금보시는전자책에소유권한을표시한문구가없거나타인의소유권한을표시한 문구가있다면위법하게사용하고있을가능성이높습니다. 이경우저작권법에의해 불이익을받으실수있습니다. 다양한기기에사용할수있습니다. 또한한빛미디어사이트에서구입하신후에는횟수에 관계없이내려받으실수있습니다. 한빛미디어전자책은인쇄, 검색, 복사하여붙이기가가능합니다. 전자책은오탈자교정이나내용의수정 보완이이뤄지면업데이트관련공지를이메일로 알려드리며, 구매하신전자책의수정본은무료로내려받으실수있습니다. 이런특별한권한은한빛미디어사이트에서구입하신독자에게만제공되며, 다른 사람에게양도나이전은허락되지않습니다.
차례 01 Elasticsearch 시작하기 1 1.1 Elasticsearch 란? 1 1.2 Elasticsearch 의특징 2 02 Elasticsearch 설치및구성하기 4 2.1 Elasticsearch 주요용어 4 2.2 Elasticsearch 설치하기 6 2.3 Elasticsearch Standalone 구성하기 10 2.4 Elasticsearch Cluster 구성하기 21 2.5 Elasticsearch Node 구성의이해 32 2.6 Elasticsearch Route 기능의이해 33 2.7 Elasticsearch REST API 알아보기 36 2.8 Elasticsearch Index Settings 알아보기 41 2.9 Elasticsearch Index Mappings 알아보기 44 03 Elasticsearch 색인하기 52 3.1 Index Settings 설정하기 52 3.2 Index Schema Mappings 설정하기 55 3.3 Index 생성하기 65 3.4 색인하기 69
04 Elasticsearch 검색하기 90 4.1 검색결과속성 90 4.2 기본검색하기 91 4.3 복합검색하기 120 4.4 검색결과 Paging 127 4.5 검색결과 Filtering 131 4.6 검색결과 Sorting 134 4.7 검색결과 Faceting 138 4.8 검색결과 Highlighting 146 4.9 검색질의 Boosting 151 05 Elasticsearch Site Plugin 활용 159 5.1 Marvel Plugin 159 5.2 Head Plugin 160 5.3 Bigdesk Plugin 161 5.4 Sense 163 5.5 기타 Site Plugin 164
1 Elasticsearch 시작하기 지금까지검색엔진개발은매우어려운기술분야로인식되어일부국한된개발자의영역으로자리하였다. 국내는대형포털등을제외하고는일부벤더중심의검색솔루션이활성화되어있지만, 외국은오픈소스기반의검색엔진을많이사용하는추세다. 최근국내에서도이런오픈소스검색엔진을기반으로검색서비스를전환하거나구축하려는곳이많아지고있다. 이것은오픈소스검색엔진인 elasticsearch와 solr가검색서비스시장의많은부분에사용되고있기때문이다. 특히 elasticsearch 는쉬운설치와우수한성능그리고빅데이터에대한실시간검색이가능하다는점에서주목받고있다. 오픈소스검색엔진덕분에이제는검색엔진또는서비스개발이누구나가능하게 되었다. 검색서비스를사용해본사람이라면 elasticsearch 나 solr 를이용해쉽고 빠르게서비스를구축할수있다. 이책에서는 elasticsearch 를이용한검색엔진구성과설정, 색인그리고검색까지 모든기초과정이포함되어있다. 책에나온기본쇼핑몰예제를따라해보면서검색 의기본기능을이해하는데도움이되길바란다. 1.1 Elasticsearch 란? 셰이배논 Shay Bannon 이시작한오픈소스검색서버프로젝트로, JSON 기반의비정형데이터분산검색과분석을지원한다. 이검색엔진은실시간검색서비스지원과분산및병렬처리그리고멀티테넌시 Multitenancy 기능을제공하며, 다양한기능을플러그인 Plugin 형태로구현하여적용할수있는것이큰특징이다. 1 장 Elasticsearch 시작하기 1
또한, 아마존웹서비스 AWS, Amazon Web Services 의클라우드서비스와빅데이터처리를위한하둡 Hadoop 연동도지원하고있다. elasticsearch는현재웹문서검색, 소셜데이터분석, 쇼핑몰검색등다양한서비스에서사용되고있으며, 앞으로도중 소규모의데이터부터빅데이터까지광범위한검색과분석서비스에활용될것이다. 1.2 Elasticsearch 의특징 1.2.1 실시간검색및분석서비스지원실시간으로발생하는데이터를기반으로검색질의시결과에반영하거나분석을통한결과를실시간으로제공할수있다. 1.2.2 분산및병렬처리 데이터의분산과병렬처리가되므로실시간검색및분석을할수있고, SPOF Single Point of Failure 대응을위한높은가용성을제공한다. 1.2.3 멀티테넌시하나의클러스터내에서 indice와도큐먼트타입 Document Type 을활용하여멀티클라이언트구성및서비스를할수있다. 예를들어 shopping_mall이라는 indice 에인터넷쇼핑몰들을도큐먼트타입으로분리하여생성하거나인터넷쇼핑몰들을 indice 별로분리하여 shopping_mall이라는별칭 Alias 을생성할수있다. 1.2.4 플러그인형태구현검색엔진을직접수정하지않고필요한기능에대한플러그인을적용하여기능을확장할수있다. 예를들어외부에서제공하는형태소분석기나추가적인 REST API를구현하여적용할수있다. 1 장 Elasticsearch 시작하기 2
1.2.5 기타 그밖의특징으로는 NoSQL 과같은스키마 Schema free, JSON 기반의문서구조, 버전관리를통한충돌 Conflict 관리가가능하며, 전문검색 Full Text Search 도지원한다. 1 장 Elasticsearch 시작하기 3
2 Elasticsearch 설치및구성하기 이장에서는 elasticsearch 에서자주사용되는용어들을확인하고, elasticsearch 를 설치한후단일노드와클러스터환경으로설정하는과정을살펴본다. 2.1 Elasticsearch 주요용어 elasticsearch 에서자주사용되거나언급되는용어들로, 검색엔진을이해하는데 기초가되는표현들이므로확인하고넘어가자. 2.1.1 Index 인덱스는 elasticsearch에서데이터를저장하기위한장소로, RDBMS의데이터베이스와유사하다. index는하나또는여러개의도큐먼트타입을가질수있다. 실제소스코드나참조문서에는 indice라는용어가사용되는데 index는검색에서포괄적인의미의색인또는색인파일이고, indice는 elasticsearch 내에서물리적으로사용되는색인또는색인파일이라고보면된다. 기존검색엔진의 collection과같은의미가 indice다. 2.1.2 Shard 샤드는루씬 Lucene 을기준으로검색의기본데이터베이스가되는인덱스이며, 대량의데이터를분산처리하기위한개념으로큰크기의인덱스를여러개의작은인덱스로나누어저장하는것을말한다. 샤드는대량의데이터를단일노드에저장시저장소및성능에대한한계를해결하고, 대량의데이터를분산처리하여빠르게결과를만들수있게한다. Primary Shard: 색인시가장먼저생성되는인덱스로, 복제의기본소스가 4
된다. Replica Shard: 레플리카설정에따라 primary shard 를복제하여생성된 샤드를말한다. 2.1.3 Replica 레플리카는서비스장애발생시서비스의지속성보장과검색처리량을높이는데유용한방법이다. 레플리카는분산된다른노드에샤드와같은데이터를복제하여서비스의안정성및유연성을제공한다. 기본적으로 primary shard 에색인이완료되면이를바탕으로각노드에샤드복제 가 async 하게이루어진다. async 방식으로복제가이루어지기때문에서비스진행 중색인작업이이루어지더라도검색성능저하를최소화한다. 2.1.4 Document type 도큐먼트타입은물리적인인덱스나저장소를가지고있지않다. 다만논리적으로단일인덱스에대한서로다른목적의데이터를구분하여저장하는방법으로사용된다. 데이터베이스관점에서보면테이블과유사하며, 내장필드인 _type에따라저장된다. 2.1.5 Document 검색에서가장기본이되는데이터단위로, elasticsearch에저장되는하나의 item 또는 article을말한다. 도큐먼트는 RDBMS에서테이블내하나의 row에해당한다. 도큐먼트의필드 Field 는 RDBMS 에서테이블의 column 에해당한다. 5
2.1.6 Node 노드는 elasticsearch 를구성하는하나의서버또는데몬으로, 독립적으로동작 가능한서버를말한다. 2.1.7 Cluster 클러스터는 standalone 으로동작하는여러노드를하나의그룹으로묶어서데이 터의분산과공유를할수있도록서비스를구성하는것을말한다. 2.1.8 Elasticsearch 와 RDBMS 용어비교 다음표는 elasticsearch 의주요용어를이해하기쉽도록 RDBMS 용어와비교하여 보여준다. [ 표 2-1] Elasticsearch 와 RDBMS 용어비교 Elasticsearch index document type document field RDBMS database table row column 2.2 Elasticsearch 설치하기 elasticsearch 는 standalone 과클러스터구성이모두가능하므로두가지방법으 로설치과정을다루어본다. 2.2.1 Download 오픈소스특성상버전업그레이드가잦으므로 elasticsearch 사이트 01 를방문하 여최신버전과릴리스노트 Release Note 를꼭확인한다. 01 http://www.elasticsearch.org/download/ 6
$ wget https://download.elasticsearch.org/elasticsearch/elasticsearch/ elasticsearch-1.0.0.tar.gz 2.2.2 디렉터리구조 elasticsearch 설치파일의압축을풀면처음에는 bin, config, lib 의세개디렉 터리만존재하고, 나머지디렉터리는실행할때생성된다. [ 표 2-2] Elasticsearch 디렉터리구조 디렉터리 설명 bin elasticsearch 실행에필요한스크립트와플러그인설치스크립트가있다. config elasticsearch.yml과 logger.yml 파일이있다. lib 검색엔진에서사용하는라이브러리가있다. data 별도 path를지정하지않으면기본 index store의위치가된다. logs 검색엔진에서기록하는로그파일의위치다. plugins 검색엔진에서사용하는모든플러그인이설치되는위치다. work 임시파일경로다. 2.2.3 실행 elasticsearch는두가지방법으로실행할수있다. 하나는 foreground 방법으로이방법을실행하면실행로그가화면에찍히면서올라간다. 다른하나는 background 방법으로실행시아무런변화가없다. $ tar xvzf elasticsearch-1.0.0.tar.gz $ cd elasticsearch-1.0.0 $ bin/elasticsearch -f 데몬실행을관리하기위해다음과같은옵션을제공한다. 7
[ 표 2-3] 추가실행옵션 옵션 설명 -Des.config elasticsearch.yml 파일을지정한다. -Des.pidfile 실행된 pid를저장할파일을지정한다. -Des.foreground foreground로실행할지지정한다. -Des.path.home elasticsearch의 home 디렐터리를지정한다. 2.2.4 실행후 log 확인 백그라운드로실행한후정상적으로실행되었는지로그내용을확인한다. 다음은 정상적으로실행되었을때로그메시지다. $ tail -f logs/elasticsearch.log [2014-02-14 12:37:27,074][INFO ][node ] [standalone] version[1.0.0], pid[2289], build[a46900e/2014-02-12t16:18:34z] [2014-02-14 12:37:27,075][INFO ][node ] [standalone] initializing... [2014-02-14 12:37:27,082][INFO ][plugins ] [standalone] loaded [], sites [bigdesk, browser, head, HQ, inquisitor] [2014-02-14 12:37:29,563][INFO ][node ] [standalone] initialized [2014-02-14 12:37:29,563][INFO ][node ] [standalone] starting... [2014-02-14 12:37:29,661][INFO ][transport ] [standalone] bound_address {inet[/127.0.0.1:9300] publish_address {inet[localho st/127.0.0.1:9300]} [2014-02-14 12:37:32,720][INFO ][cluster.service ] [standalone] new_master [standalone][xeh7k7ytqbwlufhvc1zj-a][jeong-ui-macbook-pro.local][inet[localho st/127.0.0.1:9300]]{master=true reason: zen-disco-join (elected_as_master) [2014-02-14 12:37:32,743][INFO ][discovery ] [standalone] elasticsearch/xeh7k7ytqbwlufhvc1zj-a [2014-02-14 12:37:32,762][INFO ][http ] [standalone] 8
bound_address {inet[/127.0.0.1:9200] publish_address {inet[localho st/127.0.0.1:9200]} [2014-02-14 12:37:33,367][INFO ][gateway ] [standalone] recovered [2] indices into cluster_state [2014-02-14 12:37:33,368][INFO ][node ] [standalone] started 2.2.5 실행스크립트구성하기클러스터구성으로여러대의노드를관리할때노드별로실행하거나중지하는것은매우비효율적인방법이다. 노드를효율적으로관리하려면다음과같은실행스크립트를작성하여사용한다. [start.sh 작성 ] #!/bin/bash export ES_HEAP_SIZE=256m export ES_HEAP_NEWSIZE=128m export JAVA_OPT="-server -XX:+AggressiveOpts -XX:UseCompressedOops -XX:MaxDirectMemorySize -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:+CMSParallelRemarkEnabled -XX:CMSInitiatingOccupancyFraction=75 -XX:+UseC MSInitiatingOccupancyOnly" ES=/home/es/app/elasticsearch $ES/bin/elasticsearch -Des.pidfile=$ES/bin/es.pid -Des.config=$ES_NODE/config/elasticsearch.yml -Djava.net.preferIPv4Stack=true -Des.max-open-files=true > /dev/null 2>&1 & $ES 변수는실제설치된경로로수정해야한다. 9
[stop.sh 작성 ] #!/bin/bash ES=/home/es/app/elasticsearch /bin/kill `cat < $ES/bin/es.pid` $ES 변수는실제설치된경로로수정해야한다. 2.3 Elasticsearch Standalone 구성하기 이절에서는 elasticsearch 데몬을하나구성하여설정하는과정을살펴본다. 이를 바탕으로클러스터구성까지확장하므로이번절의기본설정을잘이해하도록한다. 2.3.1 Cluster 명설정이설정은 standalone 구성시필요하지않으나관리적인면에서설정하는것을추천한다. 각노드를클러스터명기준으로그루핑하여서비스하므로, 이름이다르거나틀릴경우정상적으로그루핑되지않는다. cluster.name 은 elasticsearch 실행시 data 디렉터리밑에같은이름의디렉터 리를생성한다. 이를바탕으로같은클러스터의노드들은 data 디렉터리의클러스 터명아래로색인데이터를저장한다. cluster.name: cluster_standalone 을지정하지않으면 elasticsearch 로자동 생성된다. 2.3.2 Node 명설정노드명은클러스터구성시노드구분을위해설정하며, 관리의편리성과개발의직관성을높여준다. 별도로설정하지않으면내부적으로자동생성되지만추천하지않는다. 10
node.name: standalone 2.3.3 Node 역할설정각노드는마스터노드 Master Node 와데이터노드 Data Node, 로드밸런서노드 Load Balancer Node, 클라이언트노드 Client Node 의네가지역할을한다. 노드구성에대한자세한내용은뒤에서다루고 02, 여기에서는각노드의역할설정만설명한다. 싱글노드구성을위해마스터노드와데이터노드설정을모두 true 로한다. node.master: true node.data: true 마스터로설정되면클러스터와노드에대한정보와상태를관리하고, 인덱스 와샤드에대한 coordination 을수행한다. 데이터로설정되면자신의노드에 색인데이터를저장할수있다. 2.3.4 Index Shard 와 Index Replica 설정 샤드와레플리카의기본값은각각 5 와 1 로구성된다. 하지만단일구성에서는복 제설정을하더라도할당할노드가없으므로레플리카설정은 0 으로한다. index.number_of_shards: 5 index.number_of_replicas: 0 인덱스샤드는색인저장소로사용되는인덱스를물리적으로작은단위의샤드 에분산해서저장하기위해설정하며, 인덱스레플리카는장애가발생하거나 샤드가깨졌을때복구와대응을하기위해설정한다. 02 2.5 Elasticsearch node 구성의이해참고 11
2.3.5 Index 기타설정 elasticsearch에는기본설정외에도다양한설정값이있다. 기본설정에대한정보를제외하고, 대부분의설정정보는자세히나와있지않다. 자세한내용을알려면소스코드를보거나 elasticsearch에서제공하는웹사이트의 guide 문서 03 를참고한다. 하지만이런상세한설정을하지않더라도기본설정만으로중소규모사이트는구성할수있다. [ 표 2-4] 인덱스기타설정 기본설정값 설명 index.mapper.dynamic: true 자동으로필드매핑을설정한다. index.refresh_interval: "1s" 색인 operation에대한실시간검색반영을위한주기설정이다. action.auto_create_index: true 자동인덱스생성에대한설정으로패턴을지원한다. action.disable_shutdown: true REST API를이용하여노드 shutdown 기능을활성화한다. 2.3.6 Network 설정네트워크설정은클라이언트와서버간통신을위해프로토콜 Protocol 과포트 Port 정보를구성한다. elasticsearch에서는클라이언트개발을위한접근이쉽도록대부분의 API를 REST 방식으로지원하며, JSON 기반의데이터형을사용한다. [ 표 2-4] 네트워크기본설정 기본설정값 설명 network.host: localhost IP 정보로설정한다. transport.tcp.port: 9300 TCP 기본포트로, 변경할수있다. transport.tcp.compress: true TCP 통신시데이터압축을설정한다. http.port: 9200 http(rest API) 기본포트로, 변경할수있다 http.enabled: true http(rest API) 사용을활성화한다. 03 http://www.elasticsearch.org/guide/ 12
2.3.7 Gateway 설정게이트웨이모듈설정에서는클러스터의메타정보와인덱스설정, 매핑정보등을어떻게저장하고운영할지구성하게된다. 이를바탕으로하나또는전체노드를재시작할때저장된정보를이용하여서비스가안전하게운영되도록해준다. gateway.type: local 게이트웨이타입 Gateway Type 은색인저장소유형으로사용하는스토어타입 Store Type 과는다른설정으로 local, shared fs, hadoop 그리고 s3의 4가지유형을제공한다. 현재 elasticsearch에서는 local gateway를추천하고, 이외타입들은삭제될예정이나레거시코드 Legacy Code 를지원하기위해아직남아있다. 2.3.8 Discovery 설정클러스터내에서노드간통신과마스터노드관리를설정하는역할을담당한다. standalone 구성에서는별로필요하지않으나클러스터구성때매우중요한역할을담당한다. 특히네트워크통신을요구하는클러스터구성에서는데이터손실이발생할수있기때문에이설정이더욱중요하다. discovery.zen.ping.multicast.enabled: false # 같은네트워크구간에있는모든노드와 discovery 통신을한다. discovery.zen.minimum_master_nodes: 2 #master 역할을수행할노드의최소단위를지정한다. discovery.zen.ping.timeout: 3s discovery.zen.ping.unicast.hosts: ["localhost:9300","localhost:9301","localho st:9302"] 13
multicast.enabled 설정은같은네트워크구간에있는모든노드와불필요한트래픽을유발하므로이를방지하기위해 true로설정하는것을추천한다. minimum_master_nodes 설정은 master 역할을수행할최소단위의노드크기를지정하게된다. 데이터손실및서비스안정성을확보하기위해최소 2개이상설정하는것을추천한다. 그외에는서버구성과특성에맞춰서설정한다. 2.3.9 elasticsearch.yml 작성 이제본격적인설정작업을해보자. attribute 와 value 작성시콜론 (:) 과띄어쓰 기에주의해야한다. 속성명과콜론은붙이고, 값은한칸띄어서쓴다. 형식 ) ATTRIBUTE.NAME: VALUE 콜론뒤에띄어쓰기없이값을입력하면 elasticsearch를실행하여설정값을로딩할때오류가발생할수있다. $ vi config/elasticsearch.yml [elasticsearch.yml] node.name: standalone node.master: true node.data: true index.number_of_shards: 5 index.number_of_replicas: 0 index.mapper.dynamic: true index.refresh_interval: "1s" 14
action.auto_create_index: true # 패턴형식의인덱스명생성판단설정이다. settings, mappings 정보없이바로문서를등록할경우자동으로인덱스생성여부결정한다. action.disable_shutdown: true network.host: localhost transport.tcp.port: 9300 transport.tcp.compress: true http.port: 9200 http.enabled: true gateway.type: local 2.3.10 실행및확인 터미널을빠져나온후에도 elasticsearch 데몬을계속실행시키기위해백그라운드 로실행한다. $ bin/elasticsearch -Des.pidfile=es.pid > /dev/null 2>&1 & 실행후정상적으로 elasticsearch 데몬이동작하는지 REST API 를이용하여노드 정보를확인한다. $ curl -XGET http://localhost:9200/_nodes?pretty=true 다음은데몬이정상적으로실행되었을때결과값이다. 15
[ 실행결과 ] { "cluster_name" : "elasticsearch", "nodes" : { "el_3stjkrvc0mzvmcyd4kg" : { "name" : "Zzzax", "transport_address" : "inet[/192.168.0.117:9300]", "host" : "jeong-ui-macbook-pro.local", "ip" : "192.168.0.117", "version" : "1.0.0", "build" : "a46900e", "http_address" : "inet[/192.168.0.117:9200]", "settings" : { "path" : { "logs" : "/Users/hwjeong/server/app/elasticsearch/elasticsearch- 1.0.0/logs", "home" : "/Users/hwjeong/server/app/elasticsearch/ elasticsearch-1.0.0" "cluster" : { "name" : "elasticsearch" "foreground" : "yes", "name" : "Zzzax" "os" : { "refresh_interval" : 1000, "available_processors" : 8, "cpu" : { "vendor" : "Intel", "model" : "MacBookPro10,1", 16
"mhz" : 2400, "total_cores" : 8, "total_sockets" : 8, "cores_per_socket" : 16, "cache_size_in_bytes" : 256 "mem" : { "total_in_bytes" : 8589934592 "swap" : { "total_in_bytes" : 5368709120 } "process" : { "refresh_interval" : 1000, "id" : 2383, "max_file_descriptors" : 10240, "mlockall" : false "jvm" : { "pid" : 2383, "version" : "1.6.0_65", "vm_name" : "Java HotSpot(TM) 64-Bit Server VM", "vm_version" : "20.65-b04-462", "vm_vendor" : "Apple Inc.", "start_time" : 1392354224036, "mem" : { "heap_init_in_bytes" : 268435456, "heap_max_in_bytes" : 1060372480, "non_heap_init_in_bytes" : 24317952, "non_heap_max_in_bytes" : 136314880, "direct_max_in_bytes" : 1060372480 17
"gc_collectors" : [ "ParNew", "ConcurrentMarkSweep" ], "memory_pools" : [ "Code Cache", "Par Eden Space", "Par Survivor Space", "CMS Old Gen", "CMS Perm Gen" ] "thread_pool" : { "generic" : { "type" : "cached", "keep_alive" : "30s" "index" : { "type" : "fixed", "min" : 8, "max" : 8, "queue_size" : "200" "get" : { "type" : "fixed", "min" : 8, "max" : 8, "queue_size" : "1k" "snapshot" : { "type" : "scaling", "min" : 1, "max" : 4, "keep_alive" : "5m" "merge" : { "type" : "scaling", "min" : 1, "max" : 4, 18
"keep_alive" : "5m" "suggest" : { "type" : "fixed", "min" : 8, "max" : 8, "queue_size" : "1k" "bulk" : { "type" : "fixed", "min" : 8, "max" : 8, "queue_size" : "50" "optimize" : { "type" : "fixed", "min" : 1, "max" : 1 "warmer" : { "type" : "scaling", "min" : 1, "max" : 4, "keep_alive" : "5m" "flush" : { "type" : "scaling", "min" : 1, "max" : 4, "keep_alive" : "5m" "search" : { 19
"type" : "fixed", "min" : 24, "max" : 24, "queue_size" : "1k" "percolate" : { "type" : "fixed", "min" : 8, "max" : 8, "queue_size" : "1k" "management" : { "type" : "scaling", "min" : 1, "max" : 5, "keep_alive" : "5m" "refresh" : { "type" : "scaling", "min" : 1, "max" : 4, "keep_alive" : "5m" } "network" : { "refresh_interval" : 5000, "primary_interface" : { "address" : "192.168.0.117", "name" : "en0", "mac_address" : "28:CF:E9:14:C5:C9" } 20
} } "transport" : { "bound_address" : "inet[/0:0:0:0:0:0:0:0%0:9300]", "publish_address" : "inet[/192.168.0.117:9300]" "http" : { "bound_address" : "inet[/0:0:0:0:0:0:0:0%0:9200]", "publish_address" : "inet[/192.168.0.117:9200]", "max_content_length_in_bytes" : 104857600 "plugins" : [ ] 2.4 Elasticsearch Cluster 구성하기 이절에서는앞절에서구성한데몬을바탕으로클러스터를구성해본다. 2.4.1 Prerequisite 단일서버에세개의노드를하나의클러스터로구성한다. 같은버전의 elasticsearch 폴더를 node1 과 node2, node3 으로복사해서준비한다. [ 노드생성 ] $ cp rf elasticsearch-1.0.0 node1 $ cp rf elasticsearch-1.0.0 node2 $ cp rf elasticsearch-1.0.0 node3 2.4.2 Configure 서버 1 대에 elasticsearch instance 를세개나구성하므로각노드설정시 node. name 과포트설정에주의한다. 21
[node1 에대한 elasticsearch.yml 설정 ] cluster.name: cluster_node node.name: node1 node.master: true node.data: true index.number_of_shards: 5 index.number_of_replicas: 0 index.mapper.dynamic: true index.refresh_interval: "1s" action.auto_create_index: true action.disable_shutdown: true network.host: localhost transport.tcp.port: 9300 transport.tcp.compress: true http.port: 9200 http.enabled: true gateway.type: local discovery.zen.ping.multicast.enabled: false discovery.zen.minimum_master_nodes: 2 discovery.zen.ping.unicast.hosts: ["localhost:9300","localhost:9301","localho st:9302"] [node2 에대한 elasticsearch.yml 설정 ] cluster.name: cluster_node node.name: node2 22
node.master: true node.data: true index.number_of_shards: 5 index.number_of_replicas: 0 index.mapper.dynamic: true index.refresh_interval: "1s" action.auto_create_index: true action.disable_shutdown: true network.host: localhost transport.tcp.port: 9301 transport.tcp.compress: true http.port: 9201 http.enabled: true gateway.type: local discovery.zen.ping.multicast.enabled: false discovery.zen.minimum_master_nodes: 2 discovery.zen.ping.unicast.hosts: ["localhost:9300","localhost:9301","localho st:9302"] [node3 에대한 elasticsearch.yml 설정 ] cluster.name: cluster_node node.name: node3 node.master: true node.data: true index.number_of_shards: 5 index.number_of_replicas: 0 23
index.mapper.dynamic: true index.refresh_interval: "1s" action.auto_create_index: true action.disable_shutdown: true network.host: localhost transport.tcp.port: 9302 transport.tcp.compress: true http.port: 9202 http.enabled: true gateway.type: local discovery.zen.ping.multicast.enabled: false discovery.zen.minimum_master_nodes: 2 discovery.zen.ping.unicast.hosts: ["localhost:9300","localhost:9301","localho st:9302"] 2.4.3 실행및확인 node1 부터 node3 까지차례대로실행한다. $ node1/bin/elasticsearch -Des.pidfile=es.pid > /dev/null 2>&1 & $ node2/bin/elasticsearch -Des.pidfile=es.pid > /dev/null 2>&1 & $ node3/bin/elasticsearch -Des.pidfile=es.pid > /dev/null 2>&1 & 모든노드를실행한후클러스터구성이정상적으로되었는지확인하기위해 cluster health REST API 실행한다. $ curl -XGET http://localhost:9200/_cluster/health?pretty=true 24
[ 실행결과 ] { } "cluster_name" : "cluster_node", "status" : "green", "timed_out" : false, "number_of_nodes" : 3, "number_of_data_nodes" : 3, "active_primary_shards" : 0, "active_shards" : 0, "relocating_shards" : 0, "initializing_shards" : 0, "unassigned_shards" : 0 정상적으로클러스터링되었다면작성한설정과동일하게노드들이등록되었는지 cluster nodes info REST API 를실행하여확인한다. 기본정보가너무많이나오 기때문에설정에해당하는 settings 정보만요청한다. $ curl -XGET http://localhost:9200/_nodes?pretty=true # 전체정보를가져온다. $ curl -XGET http://localhost:9200/_nodes/settings?pretty=true #settings 정보만가져온다. 다음은정상적으로클러스터링된노드목록과정보의결과값이다. [ 실행결과 ] { "cluster_name" : "cluster_node", "nodes" : { 25
"-Rr1fhFpTy2tYjQk9qWSQw" : { "name" : "node2", "transport_address" : "inet[/127.0.0.1:9301]", "host" : "jeong-ui-macbook-pro.local", "ip" : "192.168.0.117", "version" : "1.0.0", "build" : "a46900e", "http_address" : "inet[localhost/127.0.0.1:9201]", "attributes" : { "master" : "true" "settings" : { "index" : { "mapper" : { "dynamic" : "true" "number_of_replicas" : "0", "number_of_shards" : "5", "refresh_interval" : "1s" "gateway" : { "type" : "local" "pidfile" : "es.pid", "network" : { "host" : "localhost" "node" : { "data" : "true", "master" : "true", "name" : "node2" 26
"http" : { "port" : "9201", "enabled" : "true" "transport" : { "tcp" : { "compress" : "true", "port" : "9301" } "name" : "node2", "action" : { "disable_shutdown" : "true", "auto_create_index" : "true" "path" : { "logs" : "/Users/hwjeong/server/app/elasticsearch/node2/logs", "home" : "/Users/hwjeong/server/app/elasticsearch/node2" "cluster" : { "name" : "cluster_node" "discovery" : { "zen" : { "minimum_master_nodes" : "2", "ping" : { "unicast" : { "hosts" : [ "localhost:9300", "localhost:9301", "localhost:9302" ] "multicast" : { "enabled" : "false" } 27
} } "foreground" : "yes" } "CJF0dGOYRiq7izHmq2y0wg" : { "name" : "node3", "transport_address" : "inet[/127.0.0.1:9302]", "host" : "jeong-ui-macbook-pro.local", "ip" : "192.168.0.117", "version" : "1.0.0", "build" : "a46900e", "http_address" : "inet[localhost/127.0.0.1:9202]", "attributes" : { "master" : "true" "settings" : { "index" : { "mapper" : { "dynamic" : "true" "number_of_replicas" : "0", "number_of_shards" : "5", "refresh_interval" : "1s" "gateway" : { "type" : "local" "pidfile" : "es.pid", "network" : { "host" : "localhost" 28
"node" : { "data" : "true", "master" : "true", "name" : "node3" "http" : { "port" : "9202", "enabled" : "true" "transport" : { "tcp" : { "compress" : "true", "port" : "9302" } "name" : "node3", "action" : { "disable_shutdown" : "true", "auto_create_index" : "true" "path" : { "logs" : "/Users/hwjeong/server/app/elasticsearch/node3/logs", "home" : "/Users/hwjeong/server/app/elasticsearch/node3" "cluster" : { "name" : "cluster_node" "discovery" : { "zen" : { "minimum_master_nodes" : "2", "ping" : { 29
"unicast" : { "hosts" : [ "localhost:9300", "localhost:9301", "localhost:9302" ] "multicast" : { "enabled" : "false" } } } "foreground" : "yes" } "imjtqszfs6csb_hx1an0dg" : { "name" : "node1", "transport_address" : "inet[localhost/127.0.0.1:9300]", "host" : "jeong-ui-macbook-pro.local", "ip" : "192.168.0.117", "version" : "1.0.0", "build" : "a46900e", "http_address" : "inet[localhost/127.0.0.1:9200]", "attributes" : { "master" : "true" "settings" : { "index" : { "mapper" : { "dynamic" : "true" "number_of_replicas" : "0", "number_of_shards" : "5", "refresh_interval" : "1s" 30
"gateway" : { "type" : "local" "pidfile" : "es.pid", "network" : { "host" : "localhost" "node" : { "data" : "true", "master" : "true", "name" : "node1" "http" : { "port" : "9200", "enabled" : "true" "transport" : { "tcp" : { "compress" : "true", "port" : "9300" } "name" : "node1", "action" : { "disable_shutdown" : "true", "auto_create_index" : "true" "path" : { "logs" : "/Users/hwjeong/server/app/elasticsearch/node1/logs", "home" : "/Users/hwjeong/server/app/elasticsearch/node1" "cluster" : { 31
} } } } "name" : "cluster_node" "discovery" : { "zen" : { "minimum_master_nodes" : "2", "ping" : { "unicast" : { "hosts" : [ "localhost:9300", "localhost:9301", "localhost:9302" ] "multicast" : { "enabled" : "false" } } } "foreground" : "yes" 2.5 Elasticsearch Node 구성의이해 elasticsearch 의모든노드는노드설정을통해각자의역할을부여받는다. 2.5.1 Master Node 마스터노드는클러스터구성에서전체클러스터와노드, 샤드등에대한조정자 Coordinator 역할을한다. 한클러스터내에서마스터노드는최소 2개이상으로구성하는것이좋다. 마스터로지정된노드들은처음선출된마스터노드에장애가발생할경우자동으로다음마스터노드를선출하여장애대응이가능하다. 32
node.master: true 2.5.2 Data Node 데이터노드로지정된노드는색인데이터를저장하고, 검색요청시실행되며, 실제 모든작업을수행한다. node.data: true 2.5.3 Search Loadbalancer Node 검색요청에대한트래픽분산및그결과를통합하여리턴하는역할을한다. node.master: false node.data: false 2.5.4 Client Node 클라이언트노드로지정하면 node.master 설정이 default false 로처리되므로 마스터노드로사용하지않을경우지정한다. node.client: true 2.6 Elasticsearch Route 기능의이해 2.6.1 Route 기능활용라우트는특정 path를갖는데이터를물리적으로같은공간에분류하는기능으로, 라우트를설정하면검색성능을향상할수있다. 예를들어 route path 값으로문서 33
의카테고리정보를이용하면, 같은카테고리의문서들은같은샤드로지정하여색 인및검색할수있다. No Routing 라우트를설정하지않으면모든샤드를대상으로색인과검색을수행한다. 따라서 검색처리에대한성능은라우트를적용했을때보다좋지않다. [ 그림 2-1] No Routing Routing 라우트를설정하면색인과검색을수행해야하는대상샤드를바로지정하고찾을 수있다. 라우트를설정하지않았을때보다검색처리성능이매우좋다. 34
[ 그림 2-2] Routing 2.6.2 Route 기능분산된샤드에지정한카테고리정보를이용하여카테고리별도큐먼트를지정된샤드로저장할수있으며, 카테고리정보를이용하여지정한샤드의문서를검색할수있도록지원한다. 색인필드중 unique key 에해당하는값을 routing path 로지정한다. 검색시지 정한 path( 카테고리 ) 를쿼리 Query 에줘서분산된인덱스의샤드를모두검색하지않 고지정된인덱스의샤드만검색한다. 라우팅필드 Routing Field 는스토어옵션인 yes 와 index not_analyzed 로설정 되어야한다. "routing" : { "required" : true, "path" : "market.cat_first_id" } 35