본문으로 바로가기

검색엔진 sphinx 실시간 indexing 적용

category IT를보다/쇼핑몰 2014. 4. 23. 16:13

앞선 포스트에서 오픈소스 검색엔진인 스핑크스(sphinx) 도입에대해서 작성을 하면서 실시간 백업이 업무에 필요가 없어 적용을 안했다고했는데 결국 필요한 시점이 왔다. 그래서 이번엔 스핑크스의 실시간 백업에대해서 기록을 남고 공유하려고 글을 작성한다. 실시간 백업이 필요하게된 이유는


첫째.50만개 이상의 레코드를 하루에한번 cron을 통해 인덱싱(indexing)을 하려고하니 시간이 많이걸리고 비효율적이다.


둘째.쇼핑몰 백단 업무용 페이지를 만들어야하는데(콜팀전용) 주로 읽는 테이블이 주문,주문상품,회원 테이블인데 주문상품 경우에 현재 100만개가 넘고 주문같은경우는 실시간으로 들어오기 때문에 서비스 DB 가아닌 SPHINX DB에서 읽기 위해선 실시간 백업이 필수 였다.  콜팀은 +-10분 주문에대해서 다양한 응대가능해야한다.

(다른 이야기지만 전에 실시간 주문서비스를 구축하는 회사의 스타트업 팀원으로 있었는데 그때는 50석 규모의 콜센터의 인바운드 주문을 받았다 당시엔 콜센터 구축 전문 업체의 외주로 구축한경험이있다. 전문 업체라 cs단 프로그램까지 깔끔하게 있더라는...하지만 상담원들의 실제 주문 관련 data는 웹에서 searching을 했지만.. 매월 4천여개의 영새상점들의 정산때문에 data도 민감하고, 거의 실시간으로 주문을 넣어야하니깐..)


셋째.효율적


스핑크스 메뉴얼에는 몇가지 방법이 있는데 필요한 개념만 잡으면 된다. 시간 여유 되시고 깊게 이해하기를 원하는 분들은 sphinx메뉴얼이나 "구글신"에게 물어보면 자료를 찾을 수 있겠죠. 저는 깊게 알지도 못할 뿐더러 구축에 필요한 딱 개념 정리만 하는걸로 합니다.

sphinx가 실시간 인덱싱을 할수있는 방법은 두가지입니다.

첫번째 sphinx.conf 파일에 설정을 통한 RT 인덱싱

두번째 delta 인덱싱

두번재 delta 인덱싱은 뭔가 있어보이지만  그냥 변경 사항만 백업하는 증분 백업(incremental backup) 생각하시면됩니다.  제가 적용한 방법은 delta indexing 방법  설정은 역시 sphinx.conf 파일에서 하면돼고 원리는 역시 증분 백업 생각하시면됩니다. 스핑크스 설정파일인 sphinx.conf만 잘만져서 삽질하면 어려운것은 전혀 없습니다.

일단 서비스 db에서 인덱싱할 테이블에 구조 변경이 필요합니다. 저는인덱싱할 테이블에  isdeltaindexing 이라는 이름을 가진 필드를 추가했죠. 인덱싱여부를 체크하는 필드입니다. 일단 주문 관련 테이블 기준으로 order 테이블에 추가를하고 default 를 N로 구조 변경을 했습니다

그리고 delata indexing을 위한 sphinx.conf파일이 설정이 완료되면 리눅스 시스템 효자 기능 crontab 에 2분단위로 indexer 를 동작시킴니다. 그러면 주문테이블에 레코드가 변경 되거나 새로 추가(INSERT)된 경우 가져와 그 레코만 INDEXING을 시키고 기존 sphix db에 추가를 하는방식


글로 설명하면 복잡한데 사실 간단합니다. 

일단 delta indexing 을 위한 sphinx.conf 설정파일을 올릴께요

##### sphinx.conf 파일 일부 여기서부터

source gs_order{
        type                    = mysql
        sql_host              = localhost
        sql_user              = root
        sql_pass             = iamsuper
        sql_db                 = mall
        sql_port               = 3306  # optional, default is 3306
        sql_query_pre       = SET NAMES utf8
        sql_query             = SELECT  \
                                ordno as uid ,ordno,settleprice,settlekind,nameOrder,emailOrder,nameReceiver,namePayer,adminmemo,ad
minmemo2,address1,mid,orddt,paydt,astep  from gs_order where isdeltaindexing='Y'

        sql_attr_uint =uid
        sql_field_string=ordno
        sql_field_string=settleprice
        sql_field_string=settlekind
        sql_field_string=nameOrder
        sql_field_string=emailOrder
        sql_field_string=nameReceiver
        sql_field_string=namePayer
        sql_field_string=adminmemo
        sql_field_string=adminmemo2
        sql_field_string=address1
        sql_field_string=mid
        sql_field_string=orddt
        sql_field_string=paydt
        sql_field_string=astep
 
}

#delta indexing 을 위해 추가된 항목들 ..
source gs_order_delta:gs_order{
        sql_query_pre           = SET NAMES utf8
        sql_query               = SELECT  ordno as uid,ordno,settleprice,settlekind,nameOrder,emailOrder,nameReceiver,namePayer,adm
inmemo,adminmemo2,address1,mid,orddt,paydt,astep  from gs_order where isdeltaindexing='N'
        sql_query_post=update gs_order set isdeltaindexing='Y' where isdeltaindexing='N'
        #sql_query_killlist=select uid from gs_order where isdeltaindexing='D'
}

index gs_order
{
      
        source                  = gs_order
        path                    = /home/sphinx/data/gs_order
        docinfo                 = extern
        charset_type            = utf-8
        charset_table = 0..9, A..Z->a..z, _, a..z,U+AC00..U+D7A3,U+1100..U+1159,U+1161..U+11A2,U+11A8..U+11F9,U+0021..U+002F,U+003A
..U+0040,U+005B..U+0060,U+007B..U+007E
        ngram_chars =  U+AC00..U+D7A3
        ngram_len               =1
        enable_star=1
        min_infix_len=2
}

##### sphinx.conf 파일 일부 여기까지



위 설정파일에 다른 옵션들은 메뉴얼을 찾아보시고 detal indexing의 핵심은 빨간색입니다. sql_query 로 인덱싱할 레코드를 가져오고 indexing을 만든 레코드는 isdeltaindexing='Y'로 update한다.


업무시간 매3분마다 설정된 크론에 등록된 쉘(sh) 파일은 이렇게 생겼습니다. 핵심은 역시 빨간색 으로 된 부분인데 sphinx 명령어 인 indexer 입니다.   gs_order_delta 를 인덱싱한후에 --merge 옵션으로 기본 인덱싱 파일에 병합 한다는말이죠.   --rotate 옵션은 serachd 가 떠있을때 사용하는 명령입니다.


sphinx_delta_indexing.sh

/usr/local/sphinx/bin/indexer gs_order_delta --rotate
/usr/local/sphinx/bin/indexer --merge gs_order gs_order_delta --rotate


sphinx.conf 파일에 설정된 gs_order 가아니라 gs_order_delta 만 indexing 하고  처음돌린 gs_order 에 merge 합니다. 

삽질이 끝난후 실제 적용을 할때는 최초 gs_order 에대한 $>indexer gs_order 로 1회 돌립니다.  그후 cron으로는 gs_order_delta 만 indexing을 한후  기존 gs_order에 merge 하면 됩니다.

처음 설정후 cron을 돌리면 merg 규칙이 깨진건지 계속적으로 merge를 하여 hdd 용량이 full 난 경험이 있습니다. 이럴때 해당 sphix db폴더 위에 설정대로라면 /home/sphinx/data/gs_order..... 관련 파일들을 전부 삭제하고 다시 돌렸읍니다.  사실  stackoverflow나 sphinx메뉴얼 검색을 하면 이런경우 대처방법이 있던데 전 무식하게 처리했습니다. *.sph ,*.spi,*.spk  *.spm .. 이런 파일들 말이죠. 참고하시길 바랍니다.


cron이 잘돌다면 sphinx db 에 접속해서 쿼리를 날려보세요  

mysql -h0 -P9306

접속후 

인덱싱된 gs_order 테이블을 조회 해보세요.  서비스 db에서 수정이나 추가가 일어나면 (isdeltaindexing만 N로 해주면됨)  새롭게 indexing된 레코드들이 인뎅싱 되는것을 확인 할 수 있습니다.  

실제 서비스 DB에서 새로운 주문 추가는 물론이고 주문 data에대한 후처리(결제상태변경,결제여부,관리자메모,배송여부,재고없는 제품 발주여부 등등...) 에대한 수정이 있으면 isdeltaindexing 필드만 N로 UPDATE해주면 됩니다.


이런식으로 상품테이블..등 필요한 테이블을 delta indexing 하면 됩니다.


결론적으로 내가 원하는건 아래 그림





기존 상품테이블,주문관련테이블  그리고 새로 추가될 콜 업무 관련 테이블 읽기는 sphinx db 에서  쓰기는 어떻게할까?  backoffice 서버와 서비스 서버는물리적으로 다른곳 에있고 서비스 서버 쇼핑몰이 솔루션이라 이거저것 처리할게 디게 많은데? 쓰기는 어떻게 해야 하나 고민중...