검색엔진의 본연의 기능이 검색기능을 소개한다.

 

한글 형태소 분석기

은전한닢 형태소분석기

  •  Mecab-ko-dic 기반으로 만들어진 한국어 형태소 분석기
  • 자바 인터페이스, 스칼라 인터페이스 두가지를 제공
  • 복합명사, 활용어의 원형 찾기가 가능하고, 시스템 사전을 통해 동작.
  • 아파치 라이선스 2.0 
  • 가장 보편적으로 사용되는 한글 형태소 분석기

설치방법

./bin/elasticsearch-plugin install https://github.com/javacafe-project/elastic-book-etc/raw/master/plugin/elasticsearch-analysis-seunjeon-6.4.3.zip 

 

설치 이후 사용은 인덱스 생성시 tokenizer 항목에 "type"을 seunjeon_tokenizer 로 설정하고, 아래 적을 분석기 설정시 제공하는 옵션을 이용해 옵션을 설정해 사용한다.

 

분석기에서 제공하는 옵션 정보는 아래와 같다.

파라미터 설명
user_wods 사용자 사진을 정의한다(기본값 : [ ])
user_dict_path 사용자 사전 파일의 경로를 설정한다. 해당 파일은 엘라스틱서치의 config폴더 밑에 생성한다.
decompoud 복합명사 분해 여부를 정의한다(기본값 : true)
deinflect 활용어의 원형을 추출한다(기본값 : true)
index_eojeol 어절을 추출한다(기본값 : true)
index_poses 추출할 품사를 정의한다. 품사의 정의는 아래 표 참고 (예 : "N", "SL" ...)
pos_tagging 품사 태깅 여부를 정의한다(키워드에 품사가 붙어나온다) 기본값은 true
max_unk_length Unknown 품사 태깅의 키워드로 뽑을 수 있는 최대 길이를 정의한다(기본값 : 8)

 

품사 태그는 아래와 같다

품사 태그명 설명
UNK 알 수 없는 단어
EP 선어말어미
E 어미
I 독립언
J 관계언/조사
M 수식언
N 체언
S 부호
SL 외국어
SH 한자
SN 숫자
V 용언
VCP 긍정지정사
XP 접두사
XS 접미사
XR 어근

 

사전 추가

복합명사 (삼성전자, 전자제품 등의 단어가 합해져 하나의 단어처럼 사용되는 것)을 검색하기 위해, 사용자가 사전을 등록할 수 있고, 이를 사용자 사전이라고 한다.

토크나이저 사용시 토크나이저 옵션 중 user_dict_path에 지정되어있는 파일을 참조해 사용자 지정 사전을 만들 수 있다.

 

사용자 사전은 Term과 Weight 형태로 구성돼 이씨으며 가중치의 값이 작을 수록 그에 따른 우선순위는 높아진다. 

즉 우선순위를 통해 복합명사일 경우 분리되지 않도록 구성이 가능하다.

1
2
3
삼성전자-100
삼성-50
전자-50
cs

위와 같이 사용사 사전에 등록할 수 있다.

 

 

Nori 형태소 분석기

루씬 프로젝트에서 제공되는 한글 형태소 분석기로, 기존 형태소 분석기에 비해 30% 이상 빠르고 메모리 사용량도 줄었으며, 시스템 전반에 영향을 주지 않게 최적화되었으며 아파치 2.0 라이선스를 채택하고 있다.

 

설치가 필요하며, 명령은 아래와 같다.

bin/elasticsearch-plugin install analysis-nori

 

Noori 분석기는 하나의 토크나이저와 두개의 토큰 필터로 구성되어있으며, 사용자 설정 사전과 불용어 처리를 위한 stopwords를 지원한다.

  • nori_part_of_speech : 토큰 필터
  • nori_readingform : 토큰 필터

nori_tokenizer 토크나이저

토크나이저는 형태소를 토큰 형태로 분리하는 데 사용한다. 두가지 파라미터를 지원한다.

  • decompressed_mode : 복합명사를 토크나이저가 처리하는 방식
  • user_dictionary : 사용자 사전 정의

1) decompound_mode : 복합명사를 처리하는 방식으로, 복합명사를 어떻게 쪼갤지 결정한다. 단어를 쪼개는 방법은 세가지 중에서 설정할 수 있다.

 

파라미터명 파라미터값 설명 예제
decompound_mode name 복합명사로 분리하지 않는다 월미도
영종도
discard 복합명사로 분리하고 원본 데이터는 삭제한다 잠실역 --> (잠실, 역)
mixed 복합명사로 분리하고 원본 데이터도 유지한다 잠실역 --> (잠실, 역, 잠실역)

2) user_dictionary

  Nori 토크나이저 는 기본 사전으로 내부적으로 세종 말뭉치와 mecab-ko-dic 사전을 사용한다. user_dictionary를 이용해 사용자가 정의한 명사를 사전에 추가 등록할 수 있다.

위치 : config/userdic_ko.txt 형태

설정하게 되면 인덱스의 tokenizer옵션의 user_dictionary 옵션에 해당 사전 파일을 명시에 사용자 사전을 추가해준다.

 

nori_part_of_speech 토큰 필터

nori_part_of_speech 토큰 필터 : 품사 태그와 일치하는 토큰을 찾아 제거하는 토큰 필터로, 문서에 존재하는 모든 명사를 역색인하는 것이 아니라 명사를 선택적으로 고를 수 있고, 이를 통해 사용하지 않는 형태소를 제거 가능하다.

중간에 해당 설정을 바꿀 수 있으며, filter 옵션의 nori_postfilter에 명시함으로써 해당 기능 사용이 가능하다.

여러 개의 Stoptag를 사용하고 싶다면 컴마(,)로 연결해 사용한다.

 

 nori_readingform 토큰 필터

문서에 존재하는 한자를 한글로 변경해 저장해주는 필터

 

트위터 형태소 분석기 

트위터에서 한글을 처리하기 위해 개발한 형태소 분석기로, 정규화, 토큰화, 스테밍, 어구 추출이 가능하다는 특징이 있다.

  • 정규화 : 입니닼ㅋㅋ --> 입니다, 사릉해 --> 사랑해
  • 토큰화 : 한국어를 처리하는 예시입니다 ㅋㅋ --> 한국어Noun, 를Josa, 처리Noun, 하는Verb, 예시Noun, 입니다Adjective, ㅋㅋ KoreanParticle
  • 스테밍 : 한국어를 처리하는 예시입니다 ㅋㅋ --> 한국어Noun, 를Josa, 처리Noun, 하는Verb, 예시Noun, 입니다Adjective, ㅋㅋ KoreanParticle
  • 어구추출 : 한국어를 처리하는 예시입니다 ㅋㅋ --> 한국어 , 처리, 예시, 처리하는 예시

분석기에 사용되는 사전은 open-korean-test 프로젝트에서 별도로 제공되며, 사전 내부의 src/main/resources/org/openkoreantext/processor/util 디렉토리에서 사전 내부의 파일을 별도로 볼 수 있다.

설치방법은 아래와 같다

./bin/elasticsearch-plugin install https://github.com/javacafe-procect/elasticc-book-etc/raw/master/plugin/elasticsearch-analysis-openkoreantext-6.4.3.0-plugin.zip

 

사전 추가

기본 제공되는 사전 외의 단어를 사용자가 직접 추가 가능. 한줄 단위로 처리되며, plugins/elasticsearch-analysis-openkoreantext/dic 디렉토리 안에 넣으면 됨.

 

인덱스 설정

플러그인 컴포넌트는 Character Filter, Token Filter, Analyzer로 구성되어 있으며, 필요에 따라 구성해 사용한다.

 

  • Character Filter : 구어체를 표준화한다. ex) 안됔ㅋㅋㅋ --> 안돼ㅋㅋㅋ
  • Tokenizer : 문장을 토큰화한다. (한국어를 처리하는 예시입니다 --> 한국어를,처리,하는,예시,입니다,ㅋㅋㅋ)
  • Token Filter 
    • openkoreantext-stemmer : 형용사, 동사를 스테밍한다(새로운 스테밍을 추가했었다 --> 새롭다, 스테밍, 을, 추가하다)
    • openkoreantext-redundant-filter : 접속사, 공백 조사, 마침표 등을 제거 --> 그리고 이것은 예시, 또는 예로써, 한국어를 처리하기 --> 예시,예,한국어,처리,하다
    • openkoreantext-phrase-editor : 어구 추출 (한국어를 처리하는 예시입니다 ㅋㅋ -> 한국어,처리,예시,처리하는예시)

사용시에는 똑같이 Analyzer에 openkoreantext-analyzer를 명시해 사용하면 된다.

검색결과 하이라이트하기

문서 검색 결과를 웹상에서 출력할때 입력한 검색어를 강조함으로써, 시각적으로 사용자가 어느 부근을 확인해야하는지 손쉽게 확인할 수 있도록 한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
PUT test_highlighting/_doc/1
{
  "title":"Harry Potter and the Deathly Hallows"
}
 
POST test_highlighting/_search
{
  "query": {
    "match": {
      "title": {
        "query":"harry"
      }
    }
  },
  "highlight": {
    "fields": {
      "title": {}
    }
  }
}
cs

위와 같이 테스트 하게 되면, 검색어가 일치하는 Haary 라는 단어를 <em> 태그로 감싼 결과를 확인 가능하다.

em 태그가 아닌 별도 태그도 이용 가능하다. 태그 쪽의 pre_tags, post_tags 항목을 수정하여 반영하면 된다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
POST test_highlighting/_search
{
  "query": {
    "match": {
      "title": {
        "query":"harry"
      }
    }
  },
  "highlight": {
    "fields": {
      "title": {}
    },
    "post_tags": ["</strong>"],
    "pre_tags": ["<strong>"]
    
  }
}
 
cs

스크립트를 이용해 동적으로 필드 추가하기

스크립팅 : 사용자가 스크립트를 이용해 특정 로직을 삽인하는 것으로, 두개 필드를 하나로 합하거나, 계산된 스코어를 특정 수식으로 재계산하는 작업이 가능.

위 스크립팅 기능을 이용해, 필드 추가나 제거 등 다양한 스크립팅이 가능하다.(필드 추가나 제거 등)

 

필드 추가는 ctx._source.인덱스이름.필드이름 = 값; 으로 작업 가능하며,

필드 제거는 ctx._source.인덱스이름.remove(필드이름) 을 통해 작업 가능하다.

 

별칭을 이용해 항상 최신 인덱스 유지하기

엘라스틱서치 클러스터를 운영하는 도중, 매핑 설저잉 변경되거나 인덱스가 깨진다면, 기존 생성된 인덱스를 삭제하고 다시 생성해야 한다.

운영중인 인덱스를 삭제하면 장애가 발생할 수 있으므로, 별칭 기능을 이용해 장애가 일어나지 않도록 작업이 가능하다. 또한 인덱스 별칭을 이용하면, 두 개 이상의 인덱스를 검색해야 할 때 한번의 요청만으로 모두 검색하도록 만들 수 있다. 

 

실제 운영중 인덱스에 문제가 생기는 경우가 많아, 이 내용은 큰 도움이 될 것으로 보인다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 인덱스 복사
POST _reindex
{
  "source": {
    "index": "test_highlighting"
  },
  "dest": {
    "index": "test_highlighting_2nd"
  }
}
 
# 인덱스 별칭 등록
POST _aliases
{
  "actions": [
    {"add": {"index": "test_highlighting", "alias":"highlighting"}},
    {"add": {"index": "test_highlighting_2nd", "alias":"highlighting"}}
  ]
}
 
# 검색 테스트
POST highlighting/_search
{}
cs

 

매일 생성되는 인덱스를 지속적으로검색하기 위해 사용할때 활용하면 효과적이다.

 

스냅숏을 이용한 백업과 복구

클러스터를 물리적으로 백업할 수있다. 물리 위치 디렉토리를 생성하고 이에 _snapshot 명령을 이용해 진행할 수 있다.

 

1
2
3
4
5
6
7
8
9
PUT _snapshot/test_highlighting
{
  "type":"fs",
  "settings": {
    "location": "/home/path/test",
    "compress":true
  }
}
 
cs

위 명령을 통해 레포지터리를 생성한다.

리포지토리는 스냅샷을 저장하는 논리적인 공간으로, 물리적으로 설정된 디렉토리 내부만 설정할 수 있다. 그리고 다양한 설정값을 지정할 수 있는데, 이부분은 아래 표를 참조하면 된다.

 

location 스냅숏의 저장 경로 설정
compress 스냅숏 생성시 압축을 수행한다. 데이터는 압축되지 않으며, 메타데이터만 압축 대상이다.
chunk_size 생성되는 파일을 특정 크기로 나누어 생성할 수 있다. 기본값은 1개이다.
max_restore_bytes_per_sec 스냅숏 복원시 속도를 설정한다. 기본값은 초당 40MB
max_snapshot_bytes_per_sec 스냅숏 복원시 속도를 설정한다. 기본값은 초당 40MB
readonly 리포지토리를 읽기 전용으로 생성한다.

리포지토리가 정상적으로 생성되고 나면 스냅숏을 생성한다.

 

1
2
3
4
5
6
7
8
 
PUT _snapshot/test_highlighting/test_highlighting_part1?wait_for_completion=true
{
  "indices": "test_highlighting",
  "ignore_unavailable": true,
  "include_global_state": false
}
 
cs

 

 

기본적으로 스냅숏 대상은 더이상 변경이 없어야한다(즉, 라이브환경(데이터 부어넣는 환경))에서 진행하면 문제가 발생할 가능성이 크다.

스냅숏 생성시, 스냅숏 이름은 유일한 값이여야 하며, 이미 존재하면 오류를 리턴한다.

복구는 아래 명령어를 통해 진행할 수 있다.

 

POST _snapshot/test_highlighting/test_highlighting_part1/_restore

 

위와 같이 수행하게 되면, test_highlighting_part1 이름으로 백업된 test_highlighting 인덱스가 복구된다.

복구할때, 복구하려는 인덱스와 동일한 이름의 인덱스가 존재해서는 안된다. 그렇게 된다면 에러가 발생하므로 복원 테스트를 수행할때는 기존 인덱스는 삭제하거나 reindex후 테스트를 진행하면 된다.

 

백업된 스냅숏은 아래의 명령을 통해 삭제 가능하다.

 

DELETE _snapshot/test_highlighting/test_highlighting_part1

 

출처 : 엘라스틱서치실무가이드

 

 

안녕하세요! 오늘은 Elasticsearch 중 저번 글에 이어(https://daedamee.tistory.com/entry/Elasticsearch-%EB%B6%84%EC%84%9D%EA%B8%B0-%EA%B0%9C%EC%9A%94?category=728526) 토크나이저 필터와 토큰 필터에 대해 알아보았습니다. 설치환경이 있으시다면 한번씩 실습해보시는것도 재미겠네요 :) 

토크나이저 필터

분석기를 구성하는 핵심 요소로,  텍스트를 검색 가능한 Token으로 분해하는 역할을 수행한다. 분석기의 전체적인 성격이 결정되는 부분!

다양한 형식의 토크나이저를 제공한다.

 

  1. Standard 토크나이저★★★★ : 엘라스틱서치에서 일반적으로 사용되는 토크나이저로, 대부분의 기호를 만나면 토큰으로 나눈다.(정확히는 Unicode Text Segmentation algorithm, http://unicode.org/reports/tr29/ 참조)
주요 옵션 옵션이름설명
max_token_length 최대 토큰 갯수를 나타낸다. 

자세한 설명 : https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-standard-tokenizer.html

 

# 테스트로 삭제시 사용

DELETE my_index

# 테스트를 위한 인덱스 생성(주의사항! analyzer를 생성하려는토큰에도 명시가 필요하다!)

PUT my_index

{

  "settings": {

    "analysis": {

      "analyzer": {

        "my_analyzer": {

          "tokenizer": "my_tokenizer"

        }

      },

      "tokenizer": {

        "my_tokenizer": {

          "type": "standard",

          "max_token_length": "4"

        }

      }

    }

  },

  "mappings": {

    "_doc":{

              "properties": {

          "text": {

            "type": "text",

            "analyzer":"my_analyzer"

 

        }

    }

  }

}

}

 

# 데이터 입력

POST my_index/_doc/1

{

  "analyzer": "my_analyzer",

  "text": "A QUICK Brown-Foxes jumped over"

}

 

# 토큰 분석

POST my_index/_analyze

{

  "analyzer": "my_analyzer",

  "text": "A QUICK Brown-Foxes jumped over"

}

 

# 직접 검색해보자

POST my_index/_search

{

  "query": {

    "query_string":

    {

    "query": "jump"

  }}

}

 

 

POST my_index/_search

{

  "query": {

    "term":

    {

    "text": "quick"

  }}

}

 

     2. Whitespace TOKENIZER

공백 문자열을 기준으로 토큰을 분리하는 분석기. (설명 생략)

3. ngram TOKENIZER

글자수를 기준으로 나누어 토크나이징 하는 토크나이저로, 글자수별로 보통 자르고, 토큰에 포함할 문자열을 지정할 수도있다.

운용 방식에 따라 검색 성능이 매우 느려질 수있으므로 주의!( 특성상 토큰이 매우 많이 만들어질 가능성이 높다

 

DELETE ngram_test_index

PUT ngram_test_index

{

  "settings": {

    "analysis": {

      "analyzer": {

        "ngram_analyzer":{

          "tokenizer":"ngram_tokenizer"

        }

      },

      "tokenizer": {

        "ngram_tokenizer":{

          "type":"ngram",

          "min_gram":3,

          "max_gram":3,

          "token_chars": [

            "letter"]

        }

      }

        }

      },

      "mappings": {

        "_doc":{

                        "properties": {

          "text": {

            "type": "text",

            "analyzer":"ngram_analyzer"

 

        }

      }

    }

}

}

 

POST ngram_test_index/_doc/1

{"text":"kimgn test 값을 넣어봅니다."}

 

POST ngram_test_index/_analyze

{"analyzer": "ngram_analyzer",

  "text":"kimgn test 값을 넣어봅니다."}

 

 

POST ngram_test_index/_search

{

  "query": {

    "term":

    {

    "text": "kim"

  }}

}

 

POST ngram_test_index/_search

{

  "query": {

    "query_string":

    {

    "query": "ki"

  }}

}

 

4. Edge Ngram Tokenizer 

모서리부터 시작한다 : 토큰의 시작부터만 ngram을 수행하는 토크나이저로, 문장의 초반 몇자까지는 검색이필요할 때 유용한 방식이다.

 

DELETE edngram_test_index

PUT edngram_test_index

{

  "settings": {

    "analysis": {

      "analyzer": {

        "ngram_analyzer":{

          "tokenizer":"ngram_tokenizer"

        }

      },

      "tokenizer": {

        "ngram_tokenizer":{

          "type":"edge_ngram",

          "min_gram":2,

          "max_gram":4,

          "token_chars": [

            "letter"]

        }

      }

        }

      },

      "mappings": {

        "_doc":{

                        "properties": {

          "text": {

            "type": "text",

            "analyzer":"ngram_analyzer"

 

        }

      }

    }

}

}

 

POST edngram_test_index/_doc/1

{"text":"kimgn test 값을 넣어봅니다."}

 

POST edngram_test_index/_analyze

{"analyzer": "ngram_analyzer",

  "text":"kimgn test 값을 넣어봅니다."}

 

 

POST edngram_test_index/_search

{

  "query": {

    "term":

    {

    "text": "im"

  }}

}

 

POST ngram_test_index/_search

{

  "query": {

    "query_string":

    {

    "query": "ki"

  }}

}

 

 

5. Keyword Tokenizer ★★

전체 입력 문자열을 하나의 키워드처럼 처리한다. 즉, 토큰화 처리를 하지 않는다. (= document당 하나의 값을 가진다)

얼핏 보면 쓸데 없어 보이지만, 통계 증 집계 사용시 필수적으로 들어가야 하는 속성으로, 주로 통계가 필요한 항목(국가, 성별 등) 에 쓰인다.

 

 

 

3.4.6 토큰 필터

 

토크나이저를 이용해 분리되고 잘린 토큰들을 변형하여 더 검색에 용이하도록 만들떄 사용됩니다.

  1. Ascii Folding 토큰 필터 : 아스키코드가 아닌 문자를 ascii코드로 변환해줍니다. ex ) ñ → n
  2. Lowercase 토큰 필터 :  토큰을 구성하는 문자열을 소문자로 변환해, 대소문자 구별없는 검색을 지원할 수 있도록 한다. : FBI → fbi
  3. Uppercase 토큰 필터 :  토큰을 구성하는 문자열을 대문자로 변환해, 대소문자 구별없는 검색을 지원할 수 있도록 한다. : fbi → FBI
  4. Stop 토큰 필터 : 불용어로 등록할 사전을 구축해서 사용하는 필터로, 검색되지 않을 단어(너무 자주 나오는 접속사 등..) 을 입력하여 불용어 사전을 구축할 수 있다.
  5. Stemmer 토큰 필터 : 영어 문장을 토큰으로 분리하고, 분리된 토큰을 원형으로 변환한다.(영어만 지원한다고 한다)
  6. Synonym 토큰 필터 : 동의어 처리를 위한 필터로, 비슷한 뜻으로 쓰이는 단어를 묶을 수 있다 ex) 애플 검색 → 아이폰 검색결과 포함 표시
  7. Trim 토큰 필터 : 앞뒤 문장에 공란이 있을 경우, 해당 공란을 trim(정리) 하여 나오지 않도록 한다. 

 

출처 : 엘라스틱서치 실무 가이드, 엘라스틱서치 공식 홈페이지 블로그, 몇가지 부가사항

안녕하세요! 또 오랜만에 인사드립니다.

최근 센티넬에 이어 다른 scale out 도구인 redis-cluster가 출시되었습니다.

ubuntu 환경에서 세팅을 하다 보니 apt-get으로 보통 설치를 진행했으나, 이렇게 설치했을 때는 ubuntu 16.04 기준, 3.1.4까지밖에 설치가 안됨을 확인하였습니다.

 

이에 redis-cluster 구성을 위해 ruby 관련 라이브러리를 설치하기 위한 유틸리티인 gem을 이용해 설치를 진행해 보았습니다.

아래와 같이 진행했습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# 설치전 저장소 업데이트
sudo apt-get update
 
# make test시 에러 발생을 막기 위한 tcl 라이브러리 설치
apt-get install tcl
 
# apt 저장소에서는 최신 버전을 제공해주지 않음. 현재는 6버전이 최신이나 테스트한 버전 설치를 위해 5.0.8로 진행 먼저 다운로드 후 압축풀기
wget http://download.redis.io/releases/redis-5.0.8.tar.gz
tar xzf redis-5.0.8.tar.gz
 
# redis 디렉토리로 진입
cd redis-5.0.8
# 시간 좀 걸림
make
 
# 설치까지 진행
make install
 
# make test를 추천함, 이후 제대로된 alias 적용 확인 위해서는 새로운 세션으로 로그인을 추천
make test
 
 
 
 
# 레디스를 루비로 설치해야 최신버전으로 설치해줌, 루비 설치
sudo apt install ruby
 
# gem명령을 통해 레디스 설치
gem install redis
 
 
# 설정 변경(서버 사양에 맞게 각종 설정을 변경해줍니다. 이부분은 차후 자세히 다룰 수있습니다)
vim /etc/redis/redis.conf
 
# maxmemory: redis가 전체 메모리에서 최대 얼마까지 사용할지를 정의합니다.
# maxmemory-policy: redis가 최대 사용 메모리를 초과하게 될때 데이터를 어떻게 삭제할지를 정의합니다.
# requirepass : 인증절차를 추가합니다.
cs

 

 

 

다음 포스팅에서는 설치 이후 운영 자동화를 위한 방안과(자동시작 등), 한서버의 여러 포트에 레디스를 띄우는 방법(테스트 환경 등을 위해)에 대해 안내드릴 수 있도록 하겠습니다!

엘라스틱서치 분석기

여기서는 올바른 검색환경 구성을 위한 분석기 구성 방법과 어떻게 사용하는 지에 대해 다룹니다.

3.4.1 텍스트 분석 개요

// 쿼리
POST _analyze
{
  "analyzer": "standard",
  "text": "this is kimgn test"
}
// 결과
{
  "tokens" : [
    {
      "token" : "this",
      "start_offset" : 0,
      "end_offset" : 4,
      "type" : "<ALPHANUM>",
      "position" : 0
    },
    {
      "token" : "is",
      "start_offset" : 5,
      "end_offset" : 7,
      "type" : "<ALPHANUM>",
      "position" : 1
    },
    {
      "token" : "kimgn",
      "start_offset" : 8,
      "end_offset" : 13,
      "type" : "<ALPHANUM>",
      "position" : 2
    },
    {
      "token" : "test",
      "start_offset" : 14,
      "end_offset" : 18,
      "type" : "<ALPHANUM>",
      "position" : 3
    }
  ]
}

"this is kimgn test" 위 테스트 문장에서 "kimg"를 검색하려고 한다면? 검색되지 않는다! 

이유 : 지금 나뉘어진 토큰 안에서는 "kimgn"은 존재해도 "kimg" 는 존재하지 않기 때문

POST kimgn_test_2/_doc/1
 "text": "this is kimgn test"}




GET kimgn_test_2/_search
{
    "from": 0,
    "query":{
      "term": {
        "text": "kimg"
      }
    }
}


GET kimgn_test_2/_search
{
    "from": 0,
    "query":{
      "term": {
        "text": "kimgn"
      }
    }
}

 

 

역색인 구조란?

 아래와 같은 저장 구조로써, 위처럼 토큰을 문서로 저장하여 문서상의 위치와 출현 빈도 등을 체크하여 저장한다.

일반적인 RDB의 검색구조

출처 : https://esbook.kimjmin.net/06-text-analysis/6.1-indexing-data

Elasticsearch의 역색인 구조

출처 : https://esbook.kimjmin.net/06-text-analysis/6.1-indexing-data

ES의 색인한다는 말 : 역색인 파일을 만든다는 뜻으로, 색인 파일에 들어갈 토큰만 변경되어 저장되고, 실제 문서의 내용은 변함없이 저장됨.

 

3.4.3 분석기의 구조

분석기의 동작 프로세스

  1. 문장을 특정한 규칙에 의해 수정한다. → CHARACTER FILETER ( HTML 태그를 지우거나, 특정한 단어를 변경하는 역할을 하는 필터)
  2. 수정한 문장을 개별 토큰으로 분리한다. → TOKENIZER FILETER (분석기 구성시 하나만 사용할 수 있으며, 텍스트를 어떻게 나눌 것인지 정의한다. )
  3. 개별 토큰을 특정한 규칙에 의해 변경한다. → 토큰화된 단어를 필터링해 사용자가 원하는 토큰으로 변환한다.

 

 

 

# 분석기를 이용한 분석 방법


POST _analyze
{
  "analyzer": "standard"
, "text": ["test"]
   
}
# 기존 필드를 이용한 분석 방법
POST portdata/_analyze
{
  "field": "banner.ngram"
, "text": ["test"]
   
}

 

색인과 검색시 분석기를 각각 사용.

색인시 사용하는 Index Analyzer와 검색시 사용되는 Search Analyzer를 구분해서 사용할 수 있다. 인덱스 생성시 색인용, 검색용 분석기를 각각 정의하고, 적용하고자 하는 필드에 원하는 분석기를 지정할 수 있다.

PUT movie_analyzer
{
  "settings": {
    "analysis": {
      "analyzer": {
        "movie_lower_test_analyzer":{
          "type":"custom",
          "tokenizer":"standard",
          "filter": [
            "lowercase"
          ]
        },
        "movie_stop_test_alalyzer":{
          "type":"custom",
          "tokenizer":"standard",
          "filter" :[
            "lowercase",
            "english_stop"
            ]
        }
      },
      "filter": {
        "english_stop":{
          "type":"stop",
          "stopwords":"_english_"
        }
      }
    }
  },
  "mappings": {
    "_doc":{
      "properties":{
        "title": {
          "type":"text",
          "analyzer":"movie_stop_test_alalyzer",
          "search_analyzer":"movie_lower_test_analyzer"
        }
      }
    }
  }
}


PUT movie_analyzer/_doc/1
{
  "title": "Harry Potter and the Chamber of Secrets"
}






POST movie_analyzer/_analyze
{
  "field": "title",
  "text": "Harry Potter and the Chamber of Secrets"
}


# AND 와 OR의 검색 차이를 보자
POST movie_analyzer/_search
{
  "query": {
    "query_string": {
      "default_operator": "AND",
      "query": "Chamber of secrets"
    }
  }
}

 

3.4.3.2 대표적인 분석기

 

  1. Standard Analyzer : 가장 기본적인 분석기로, 공백 혹은 특수기호로 토큰을 분리하고, 모든 문자를 소문자로 분리하는 토큰 필터를 사용하며, (이부터는 관계자 피셜 : 자사의 특정한 알고리즘을 통해 토크나이징을 해서 가장 추천한다고 합니다.)
  2. Whitespace Analyzer : 공백 문자열을 기준으로 토큰을 분리하는 분석기
  3. Keyword Analyzer : 전체 입력 문자열을 하나의 키워드처럼 관리한다(토큰화 작업을 하지 않는다 → 집계에 가장 많이 사용하느느 토크나이저)

 

3.4.4 전처리 필터

  Document에 들어오는 문장을 미리 데이터 정제하는 것으로, 기본적으로 HTML 태그가 있음

PUT movie_analyzer_chartest
{
  "settings": {
    "analysis": {
      "analyzer": {
        "html_strip_analyzer":{
          "tokenizer":"standard",
          "char_filter": [
            "html_strip_char_filter"
          ]
        }
        },
      "char_filter": {
        "html_strip_char_filter":{
          "type":"html_strip",
          "escaped_tags":["b"]
          }
        }
      }
    },
  "mappings": {
    "_doc":{
      "properties":{
        "title": {
          "type":"text",
          "analyzer":"html_strip_analyzer"
        }
      }
    }
  }
}


POST movie_analyzer_chartest/_analyze
{
  "field": "title",
  "text":"<span> Harry Potter</span> and the <b>Chamber</b> of Secrets"
}






GET movie_analyzer_chartest/_doc/1


# span으로 검색시 검색이 안됨!
GET movie_analyzer_chartest/_search
{
    "from": 0,
    "query":{
      "term": {
        "title": "span"
      }
    }
}

 

출처 : 엘라스틱서치 실무 가이드, 엘라스틱서치 공식 홈페이지 블로그

crontab을 통해 크롤링 배치를 걸어두려 했으나, 콘솔에서는 잘만 수행되던 것이 crontab으로 등록하면 제대로 수행되지 않는 현상이 발견되었습니다.

이렇게 제대로수행되지 않은 배치는 자꾸 메일을 낳고... 

그래서 이 메일을 확인해보았습니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
$ sudo tail -50 /var/spool/mail/root  
 
From root@localhost.localdomain  Sun Jan 28 22:56:03 2018
Return-Path: <root@localhost.localdomain>
X-Original-To: root
Delivered-To: root@localhost.localdomain
Received: by localhost.localdomain (Postfix, from userid 0)
        id EF2D0617AAA7; Sun, 28 Jan 2018 22:56:02 +0900 (KST)
From: "(Cron Daemon)" <root@localhost.localdomain>
To: root@localhost.localdomain
Subject: Cron <root@localhost> /home/kimgn/pythonstudy/kimgn_test/kimgn_bitcoin/get_bitcoin.py  > /home/kimgn/log/get_bitcoin.log
Content-Type: text/plain; charset=UTF-8
Auto-Submitted: auto-generated
Precedence: bulk
X-Cron-Env: <XDG_SESSION_ID=1640>
X-Cron-Env: <XDG_RUNTIME_DIR=/run/user/0>
X-Cron-Env: <LANG=ko_KR.UTF-8>
X-Cron-Env: <SHELL=/bin/bash>
X-Cron-Env: <PATH=/sbin:/bin:/usr/sbin:/usr/bin>
X-Cron-Env: <MAILTO=root>
X-Cron-Env: <HOME=/root>
X-Cron-Env: <LOGNAME=root>
X-Cron-Env: <USER=root>
Message-Id: <20180128135602.EF2D0617AAA7@localhost.localdomain>
Date: Sun, 28 Jan 2018 22:56:02 +0900 (KST)
 
Traceback (most recent call last):
  File "/home/kimgn/pythonstudy/kimgn_test/kimgn_bitcoin/get_bitcoin.py", line 12, in <module>
    django.setup()
  File "/home/kimgn/anaconda3/lib/python3.6/site-packages/django/__init__.py", line 19, in setup
    configure_logging(settings.LOGGING_CONFIG, settings.LOGGING)
  File "/home/kimgn/anaconda3/lib/python3.6/site-packages/django/conf/__init__.py", line 56, in __getattr__
    self._setup(name)
  File "/home/kimgn/anaconda3/lib/python3.6/site-packages/django/conf/__init__.py", line 43, in _setup
    self._wrapped = Settings(settings_module)
  File "/home/kimgn/anaconda3/lib/python3.6/site-packages/django/conf/__init__.py", line 106, in __init__
    mod = importlib.import_module(self.SETTINGS_MODULE)
  File "/home/kimgn/anaconda3/lib/python3.6/importlib/__init__.py", line 126, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 978, in _gcd_import
  File "<frozen importlib._bootstrap>", line 961, in _find_and_load
  File "<frozen importlib._bootstrap>", line 950, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 655, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 678, in exec_module
  File "<frozen importlib._bootstrap>", line 205, in _call_with_frames_removed
  File "/home/kimgn/pythonstudy/kimgn_test/kimgn_bitcoin/kimgn_bitcoin/settings.py", line 14, in <module>
    import MySQLdb
  File "/home/kimgn/anaconda3/lib/python3.6/site-packages/MySQLdb/__init__.py", line 19, in <module>
    import _mysql
ImportError: libmysqlclient.so.20: cannot open shared object file: No such file or directory
cs


확인해보니 이전 MySQL 모듈 로딩시 발생했던 에러임을 확인할 수있었습니다..

이 상황을 타개하기 위해서 crontab에도 bashrc에 등록했던 path 지정을 동일하게 해주었더니 해당 현상은 해결되었습니다.


1
2
3
4
5
$ cat /etc/crontab 
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
LD_LIBRARY_PATH="/mysql/lib/:$LD_LIBRARY_PATH"
cs


이상 간단하지만 상당히 많은 삽질(..) 을 하게했던 리눅스 관련 크론탭 설정입니다.

테스트나 스트레스 테스트 등으로 인해 MySQL 에 무한 인서트 등을 해야할 때가 간혹 있습니다. 매우 간단한 5줄(...) 짜리 코드지만, 간단히 소개해봅니다.

소스코드 설치 버전 MySQL + anaconda3 으로 테스트 진행했습니다.



1
2
3
4
5
6
7
8
9
10
11
12
13
import MySQLdb # 접속을 위해 MySQLdb 임포트
# 관련 참고 URL : http://mysql-python.sourceforge.net/MySQLdb.html#mysqldb
 
treeHit = 0
db = MySQLdb.connect(db='DB이름',
port=포트번호,host='localhost'
user="접속계정명",
password="접속비밀번호"
unix_socket="소켓이있을경우-로컬접속일경우명시없으면빼도됨"
# 앞으로 빼내서 커넥션을 한번만 수행하도록 테스트진행.
 
while interval < 50000# 몇회만큼 수행할지 결정
    interval = interval +1
    db.autocommit('on'# 오토커밋은 ON으로 변경한다. 이 옵션이 없으면 commit 없이 문장을 수행하므로 불편하다.
    db.query("""INSERT INTO test (contents,date_val) VALUES ( CEILING(RAND()*100),now());""")
    db.query("""INSERT INTO test2 (contents,date_val) VALUES ( CEILING(RAND()*100),now());""")
 
 
cs




Django + MySQL 사용시 MySQL connect library 설치 방법

Django는 2.0 이후 버전부터 default library로 mysqlclient를 사용한다. 하지만 이 버전 사용시 mysql의 라이브러리를 참조해야 하는데, 해당 정보를 가져오지 못해 에러가 나는 경우가 발생한다.



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
root@localhost  ~
$ pip install mysqlclient  
Collecting mysqlclient
  Retrying (Retry(total=4, connect=None, read=None, redirect=None)) after connection broken by 'NewConnectionError('<pip._vendor.requests.packages.urllib3.connection.VerifiedHTTPSConnection object at 0x7f73b141fdd8>: Failed to establish a new connection: [Errno -2] 이름 혹은 서비스를 알 수 없습니다',)'/simple/mysqlclient/
Installing collected packages: mysqlclient
Successfully installed mysqlclient-1.3.12
kimgn@localhost  ~
$ pip install mysql-python
Collecting mysql-python
  Retrying (Retry(total=4, connect=None, read=None, redirect=None)) after connection broken by 'NewConnectionError('<pip._vendor.requests.packages.urllib3.connection.VerifiedHTTPSConnection object at 0x7fb16050e400>: Failed to establish a new connection: [Errno -2] 이름 혹은 서비스를 알 수 없습니다',)'/simple/mysql-python/
  Using cached MySQL-python-1.2.5.zip
    Complete output from command python setup.py egg_info:
    Traceback (most recent call last):
      File "<string>", line 1, in <module>
      File "/tmp/pip-build-xfi5tabw/mysql-python/setup.py", line 13, in <module>
        from setup_posix import get_config
      File "/tmp/pip-build-xfi5tabw/mysql-python/setup_posix.py", line 2, in <module>
        from ConfigParser import SafeConfigParser
    ModuleNotFoundError: No module named 'ConfigParser'
    
    ----------------------------------------
Command "python setup.py egg_info" failed with error code 1 in /tmp/pip-build-xfi5tabw/mysql-python/
root@localhost  ~
 
 
cs


이 현상으로 인해 ipython을 통해 MySQLdb를 임포트해본 결과 임포트가 정상적으로 되지 않는다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
In [2]: import MySQLdb
---------------------------------------------------------------------------
ImportError                               Traceback (most recent call last)
<ipython-input-2-dd22983d5391> in <module>()
----> 1 import MySQLdb
 
~/anaconda3/lib/python3.6/site-packages/MySQLdb/__init__.py in <module>()
     17 from MySQLdb.release import __version__, version_info, __author__
     18 
---> 19 import _mysql
     20 
     21 if version_info != _mysql.version_info:
 
ImportError: libmysqlclient.so.20: cannot open shared object file: No such file or directory
 
해당 에러를 해결하기 위해서는 플러그인 라이브러리를 가져오기 위한 변수를 export 해주어야 한다.(참고 블로그 : http://k-flow.tistory.com/93)
 
vi ~/.bashrc
혹은 
vi /etc/profile.d/임의의sh파일
아래 문구 추가
 
 export LD_LIBRARY_PATH="MSQL라이브러리경로:$LD_LIBRARY_PATH"
 
cs


crontab등의 수행시 반영하고 싶을 경우는 crontab -e 후 해당 내용 반영

이후 수행하면 정상적으로 반영됨을 확인할 수 있다.


mysql_config 파일을 찾지 못해 설치 못되는 경우도 발생한다.


위와 같은 경우에는 PATH에 해당 경로를 삽입해주면 된다.

 export PATH="....MSQL바이너리경로:$LD_LIBRARY_PATH"

'IT etc. > Python OR Django' 카테고리의 다른 글

MySQL에 무한 인서트 하기  (0) 2018.01.03

레디스-센티넬 소개 및 설정.

redis-sentinel이란?


Redis 인스턴스 관리를 돕기 위해  디자인된 시스템으로, 레디스의 fail-over를 돕는 도구라고 보시면 됩니다.

보통 홀수로 구성하여 과반의 센티넬이 마스터 노드가 죽었다고 판단하면 후로 리플리케이션 중 하나를 master로 올리는 형태를 취합니다.


(2020.03.20 추가 : 업무에서 사용하는 관계로 블로그를 찾아보는데, 설치는 진행되지 않았더군요. Ubuntu를 기준으로 설치 스크립트를 추가합니다(매우간단..)

1
 apt install redis-sentinel






레디스가 4.0.6으로 업그레이드 되며, 관련 설정 또한 주석처리되어서 안내되어 굳이 (물론 필요한 경우는 열어야 겠지만)

sentinel 관련 레퍼런스를 안열어도 이해하기 쉽도록 변경되었습니다.

아래는 센티넬 설정파일이며, 관련해 주석을 달아 어떤 내용인지 적어두었습니다.(센티넬 설정파일의 경로는 /etc/redis/sentinel.conf 입니다)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
# Example sentinel.conf
 
# *** IMPORTANT ***
#
# By default Sentinel will not be reachable from interfaces different than
# localhost, either use the 'bind' directive to bind to a list of network
# interfaces, or disable protected mode with "protected-mode no" by
# adding it to this configuration file.
#
# Before doing that MAKE SURE the instance is protected from the outside
# world via firewalling or other means.
#
# For example you may use one of the following:
#
# bind 127.0.0.1 192.168.1.1
#
# protected-mode no
bind 123.456.789.012 127.0.0.1
# 바인드 : 자신이 통신을 받을 IP 주소 명시. ifconfig를 참조하여 IP 정의하면 됨.
# port <sentinel-port>
# The port that this sentinel instance will run on
port 26379
# 포트번호
# sentinel announce-ip <ip>
# sentinel announce-port <port>
#
# The above two configuration directives are useful in environments where,
# because of NAT, Sentinel is reachable from outside via a non-local address.
#
# When announce-ip is provided, the Sentinel will claim the specified IP address
# in HELLO messages used to gossip its presence, instead of auto-detecting the
# local address as it usually does.
#
# Similarly when announce-port is provided and is valid and non-zero, Sentinel
# will announce the specified TCP port.
#
# The two options don't need to be used together, if only announce-ip is
# provided, the Sentinel will announce the specified IP and the server port
# as specified by the "port" option. If only announce-port is provided, the
# Sentinel will announce the auto-detected local IP and the specified port.
#
# Example:
#
# sentinel announce-ip 1.2.3.4
 
# dir <working-directory>
# Every long running process should have a well-defined working directory.
# For Redis Sentinel to chdir to /tmp at startup is the simplest thing
# for the process to don't interfere with administrative tasks such as
# unmounting filesystems.
dir "/data/redis/tmp"
# 작업 디렉토리로, 디폴트는 /tmp이나, 스토리지 용량이 넓은 곳으로 이관
# sentinel monitor <master-name> <ip> <redis-port> <quorum>
#
# Tells Sentinel to monitor this master, and to consider it in O_DOWN
# (Objectively Down) state only if at least <quorum> sentinels agree.
#
# Note that whatever is the ODOWN quorum, a Sentinel will require to
# be elected by the majority of the known Sentinels in order to
# start a failover, so no failover can be performed in minority.
#
# Slaves are auto-discovered, so you don't need to specify slaves in
# any way. Sentinel itself will rewrite this configuration file adding
# the slaves using additional configuration options.
# Also note that the configuration file is rewritten when a
# slave is promoted to master.
#
# Note: master name should not include special characters or spaces.
# The valid charset is A-z 0-9 and the three characters ".-_".
sentinel myid 37a7b04d44a19db6b1dd5a85a2d148e193b567ad
 
sentinel monitor mymaster 192.168.25.104 6379 2
# 모니터할 IP와 odown 의 투표 수 기준
# sdown : 주관적인 다운, sentinel 하나만 down이라고 판단. 
# odown : 명백한 다운, 제일 마지막 숫자 이상의 센티넬이 down이라고 판단하면 결정됨.
# sentinel auth-pass <master-name> <password>
#
# Set the password to use to authenticate with the master and slaves.
# Useful if there is a password set in the Redis instances to monitor.
#
# Note that the master password is also used for slaves, so it is not
# possible to set a different password in masters and slaves instances
# if you want to be able to monitor these instances with Sentinel.
#
# However you can have Redis instances without the authentication enabled
# mixed with Redis instances requiring the authentication (as long as the
# password set is the same for all the instances requiring the password) as
# the AUTH command will have no effect in Redis instances with authentication
# switched off.
#
# Example:
#
# sentinel auth-pass mymaster MySUPER--secret-0123passw0rd
 
 
 
sentinel down-after-milliseconds mymaster 10000
# 마스터 다운 후 명백히 sdown으로 판단하는 시간으로, 디폴트는 30초이나 10초로 설정
# sentinel down-after-milliseconds <master-name> <milliseconds>
#
# Number of milliseconds the master (or any attached slave or sentinel) should
# be unreachable (as in, not acceptable reply to PING, continuously, for the
# specified period) in order to consider it in S_DOWN state (Subjectively
# Down).
#
# Default is 30 seconds.
sentinel failover-timeout mymaster 15000
 
 
# sentinel parallel-syncs <master-name> <numslaves>
#
# How many slaves we can reconfigure to point to the new slave simultaneously
# during the failover. Use a low number if you use the slaves to serve query
# to avoid that all the slaves will be unreachable at about the same
# time while performing the synchronization with the master.
sentinel auth-pass mymaster mypassword!@@#!4
# redis접속에 auth 정보가 필요할 경우 마스터의 auth정보를 명시
 
# sentinel failover-timeout <master-name> <milliseconds>
#
# Specifies the failover timeout in milliseconds. It is used in many ways:
#
# - The time needed to re-start a failover after a previous failover was
#   already tried against the same master by a given Sentinel, is two
#   times the failover timeout.
#
# - The time needed for a slave replicating to a wrong master according
#   to a Sentinel current configuration, to be forced to replicate
#   with the right master, is exactly the failover timeout (counting since
#   the moment a Sentinel detected the misconfiguration).
#
# - The time needed to cancel a failover that is already in progress but
#   did not produced any configuration change (SLAVEOF NO ONE yet not
#   acknowledged by the promoted slave).
#
# - The maximum time a failover in progress waits for all the slaves to be
#   reconfigured as slaves of the new master. However even after this time
#   the slaves will be reconfigured by the Sentinels anyway, but not with
#   the exact parallel-syncs progression as specified.
#
# Default is 3 minutes.
sentinel config-epoch mymaster 2
sentinel leader-epoch mymaster 2
# SCRIPTS EXECUTION
#
# sentinel notification-script and sentinel reconfig-script are used in order
# to configure scripts that are called to notify the system administrator
# or to reconfigure clients after a failover. The scripts are executed
# with the following rules for error handling:
#
# If script exits with "1" the execution is retried later (up to a maximum
# number of times currently set to 10).
#
# If script exits with "2" (or an higher value) the script execution is
# not retried.
#
# If script terminates because it receives a signal the behavior is the same
# as exit code 1.
#
# A script has a maximum running time of 60 seconds. After this limit is
# reached the script is terminated with a SIGKILL and the execution retried.
 
# NOTIFICATION SCRIPT
#
# sentinel notification-script <master-name> <script-path>
#
# Call the specified notification script for any sentinel event that is
# generated in the WARNING level (for instance -sdown, -odown, and so forth).
# This script should notify the system administrator via email, SMS, or any
# other messaging system, that there is something wrong with the monitored
# Redis systems.
#
# The script is called with just two arguments: the first is the event type
# and the second the event description.
#
# The script must exist and be executable in order for sentinel to start if
# this option is provided.
#
# Example:
#
# sentinel notification-script mymaster /var/redis/notify.sh
 
# CLIENTS RECONFIGURATION SCRIPT
#
# sentinel client-reconfig-script <master-name> <script-path>
#
# When the master changed because of a failover a script can be called in
# order to perform application-specific tasks to notify the clients that the
# configuration has changed and the master is at a different address.
#
# The following arguments are passed to the script:
#
# <master-name> <role> <state> <from-ip> <from-port> <to-ip> <to-port>
#
# <state> is currently always "failover"
# <role> is either "leader" or "observer"
#
# The arguments from-ip, from-port, to-ip, to-port are used to communicate
# the old address of the master and the new address of the elected slave
# (now a master).
#
# This script should be resistant to multiple invocations.
#
# Example:
#
# sentinel client-reconfig-script mymaster /var/redis/reconfig.sh
 
daemonize yes
pidfile "/var/run/sentinel.pid"
logfile "/data/redis/log/sentinel.log"
# 데몬화를 위한 옵션
 
cs


Sentinel 부팅시 실행을 위한 옵션(redis 실행 파일을 복사해서 사용


아래는 센티넬을 손쉽게 사용하기 위해 시작시 수행되도록 /etc/init.d에 설정하는 쉘 파일입니다. 아래와 같이 설정하여 더욱 편하게 구동 및 재구동, 셧다운을 진행하실 수 있습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
#!/bin/sh
#Configurations injected by install_server below....
 
EXEC=/redis-4.0.6/src/redis-sentinel
CLIEXEC=/redis-4.0.6/src/redis-cli
PIDFILE=/var/run/sentinel.pid
CONF="/etc/redis/sentinel.conf"
REDISPORT="26379"
###############
# SysV Init Information
# chkconfig: - 58 74
# description: redis_6379 is the redis daemon.
### BEGIN INIT INFO
# Provides: redis_6379
# Required-Start: $network $local_fs $remote_fs
# Required-Stop: $network $local_fs $remote_fs
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Should-Start: $syslog $named
# Should-Stop: $syslog $named
# Short-Description: start and stop redis_6379
# Description: Redis daemon
### END INIT INFO
 
 
case "$1" in
    start)
        if [ -f $PIDFILE ]
        then
            echo "$PIDFILE exists, process is already running or crashed"
        else
            echo "Starting Redis Sentinel server..."
            $EXEC $CONF
        fi
        ;;
    stop)
        if [ ! -f $PIDFILE ]
        then
            echo "$PIDFILE does not exist, process is not running"
        else
            PID=$(cat $PIDFILE)
            echo "Stopping ..."
            $CLIEXEC -p $REDISPORT shutdown
            while [ -/proc/${PID} ]
            do
                echo "Waiting for Redis Sentinel to shutdown ..."
                sleep 1
            done
            echo "Redis Sentinel stopped"
        fi
        ;;
    status)
        PID=$(cat $PIDFILE)
        if [ ! -/proc/${PID} ]
        then
            echo 'Redis Sentinel is not running'
        else
            echo "Redis Sentinel is running ($PID)"
        fi
        ;;
    restart)
        $0 stop
        $0 start
        ;;
    *)
        echo "Please use start, stop, restart or status as first argument"
        ;;
esac
 
cs



실행방법

$ redis-sentinel /path/to/sentinel.conf


OR


$ redis-server /path/to/sentinel.conf --sentinel




Automatic FailOver 테스트

테스트 구성


REDIS

Port : 6379

REDIS-sentinel

Port : 26379

MonitoringREDIS

Port : 6379

REDIS-sentinel

Port : 26379

MonitoringREDIS

Port : 6379

REDIS-sentinel

Port : 26379

MonitoringreplicationingSLAVE1MASTERSLAVE2


replicationing

시나리오


sentinel 실행

master shutdown

failover 확인

sentinel 실행


/etc/init.d/sentinel_26379 start




master shutdown


 /REDIS/PATH/src/redis-cli 


127.0.0.1:6379> shutdown

not connected> exit

failover 확인




Sentinel 구성시 주의사항



1. bind 설정 필수 필요

다수 센티널 구성시, bind설정을 통해 서로 통신이 가능하게끔 방화벽 오픈 등을 설정해야 합니다..

2. master-slave 간 비밀번호 동기화

master-slave간 auth 키(비밀번호)가 같아야 HA작동시 무리없이 리플리케이션을 옮겨서 붙습니다.

3. master node에도 auth변수 저장

마스터가 죽었다가 다시 살아날 시 자동으로 리플리케이션으로 설정되는데, 이 때 리플리케이션 정상 연결을 위하여 리플리케이션 auth(비밀번호) 변수 지정이 필요합니다.




+ Recent posts