1. 노드(node)란?

엘라스틱에서 분산처리모델에서 알아보도록 하자. 분산처리에 앞아서 가장 먼저 알아야 할 것이 바로 노드(node)이다. 노드란 무엇인가? 노드의 특징은 크게 3가지로 정의할 수 있다.

  • 노드는 엘라스틱 서치의 인스턴스(instance)이다.
  • 노드는 자신만의 이름을 갖는다
  • 노드는 가동할 때 자신의 유일키(UID)를 갖는다.

노드는 엘라스틱 서치의 인스턴스이다. 즉 jvm에서 자신만의 프로세스를 갖는 다는 말이다. 또한 노드는 elasticsearch.yml에서 node.name 을 통해서 이름을 정할 수 있고 실행시 이름을 부여할 수도 있다.

/bin/elasticsearch -E node.name=master_01

위와 같이 실행시 옵션으로 노드명을 부여할 수 있다.

2. 클러스터(Cluster)란?

엘라스틱에서의 모든 것을 클러스터 내에 생성된다. 따라서 모든 노드는 클러스트에 포함된다. 클러스트는 이름을 가지고 있다. 디폴트명은 elasticsearch이다. 클러스트도 역시 application.yml에서 cluster.name에서 설정하거나 실행시 부여할 수 있다.

./bin/elasticsearch -E node.name=master_01 -E cluster.name=main_cluster_1

모든 클러스트는 cluster state 라는 참조 정보를 가지고 있다. 이 cluster state는 각 노드안에 저장된다.

cluster

노드안에 있는 cluster state는 결코 수정이 불가능하다.

3. 슬레이브 노드 추가

노드에는 마스터 노드(Master Node)라는 것이 있다. 노드 한개만 처음 실행할 때 그 노드는 마스터 노드가 된다(만약 이것을 막으려면 node.master:false 로 설정해야 한다) 노드는 마스터노드를 선출하여 결정한다. 만약 유일한 노드라면 그 노드가 마스터 노드가 된다.

그리고 데이타 노드(Data Node)가 있다. 이것은 말 그대로 데이터를 저장하는 노드이다. 그럼 노드 하나면 실행하면 마스터노드이자 데이터 노드가 되는 것이다. 즉 여러개의 노드로 구성될 경우 한 노드는 마스터, 나머지는 데이터노드로 지정할 수 있다.

cluster

그림과 같이 master_node_1은 마스터 노드이자 데이터 노드가 된 경우다. 우리고 PUT, DELETE등으로 인덱스를 추가하거나 삭제되면 데이터를 담고 있는 노드는 cluster state를 업데이트 하고 그 응답을 클라이언트에 돌려준다.

만약 두번째 노드를 생성하면 어떻게 될 것인가? elasticsearch를 복사후에 새로운 노드로 실행시켜보자.

./bin/elasticsearch -E node.name=slave_01 -E cluster.name=main_cluster_1

cluster_name은 이전에 master_01에서 만든 main_cluster_1으로 했다. 실행되면 다음과 같은 에러가 반복되서 출력됨을 확인할 수 있다.


[2018-03-12T21:55:00,738][INFO ][o.e.d.z.ZenDiscovery     ] [slave_01] failed to send join request to master [{master_01}{IGp-s0MnRveYsX1q0xh_iA}{cV-g8WUJReahGervsb_1AQ}{127.0.0.1}{127.0.0.1:9300}], reason [RemoteTransportException[[master_01][127.0.0.1:9300][internal:discovery/zen/join]]; nested: IllegalArgumentException[can't add node {slave_01}{IGp-s0MnRveYsX1q0xh_iA}{A2QxhezXQPqWRRtwNQn_Uw}{127.0.0.1}{127.0.0.1:9301}, found existing node {master_01}{IGp-s0MnRveYsX1q0xh_iA}{cV-g8WUJReahGervsb_1AQ}{127.0.0.1}{127.0.0.1:9300} with the same id but is a different node instance]; ]

이런 에러가 발생한 것은 우리가 기존에 elasticsearch를 그냥 복사해서 사용해서 그렇다. 그 안에 이미 data 디렉토리가 슬레이드도 같아서 생긴 문제다. 이럴때는 슬레이브에 있는 data 디렉토리를 삭제해주어야 한다.

다음 세컨드 노드에서는 포트를 9201로 변경하도록 하겠다.

http.port: 9201

이제 세컨드 노드를 재시작하면 정상가동되고 127.0.0.1:9200 은 마스터 127.0.0.1:9201은 슬레이브로 구성되어 있다.


[2018-03-23T22:46:48,196][INFO ][o.e.c.s.ClusterService   ] [slave_01] detected_master {master_01}{YQLO20xvSjGDIBLKuHg4Lg}{Ka9fgfy5RRmkk9f9Yv5PzA}{127.0.0.1}{127.0.0.1:9300}, added {{master_01}{YQLO20xvSjGDIBLKuHg4Lg}{Ka9fgfy5RRmkk9f9Yv5PzA}{127.0.0.1}{127.0.0.1:9300},}, reason: zen-disco-receive(from master [master {master_01}{YQLO20xvSjGDIBLKuHg4Lg}{Ka9fgfy5RRmkk9f9Yv5PzA}{127.0.0.1}{127.0.0.1:9300} committed version [19]])

정상적으로 붙으면 detected_master 라고 보인다. 이제 실제 잘 되는지 테스트해보자

4. 마스터 - 슬레이브 테스트

위에서 우리는 마스터는 localhost:9200 슬레이브는 localhost:9201 으로 설정했다. 각각 브라우저로 접속하면 각각 정보가 잘 보일것이다.

그러면 마스터에 인덱스를 추가해보도록 하자. 마스터에 추가하고 슬레이브에서 그 인덱스가 나오면 성공한 것이다.

curl -XPUT "http://localhost:9200/my_index/doc/1" -H "Content-Type: application/json" -d '
{
    "username": "harrison",
    "comment": "Mt favorite movie is Star Wars!"
}'

마스터에 정상적으로 들어가면 이제 위에 인덱스를 슬레이브에서 조회해보자.

curl -XGET "http://localhost:9201/my_index/_search" -H "Content-Type: application/json"
{
  "took": 4,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": 1,
    "max_score": 1,
    "hits": [
      {
        "_index": "my_index",
        "_type": "doc",
        "_id": "1",
        "_score": 1,
        "_source": {
          "username": "harrison",
          "comment": "Mt favorite movie is Star Wars!"
        }
      }
    ]
  }
}

정상적으로 슬레이브에서 잘 보인다. 마스터 슬레이브 구성이 성공한 것이다. 슬레이브에서 추가,수정,삭제해도 마스터에 바로 반영이 된다. 그러면 슬레이브를 죽인 상태에서 마스터에 추가하고 슬레이브를 살리면 슬레이브에서 가져오는지 확인해보자.

curl -XPUT "http://localhost:9200/my_index/doc/2" -H "Content-Type: application/json" -d '
{
    "username": "richard",
    "comment": "Mt favorite movie is Golira!"
}'

마스터에 추가하고 조회하면 아래에 같이 2건이 나온다.

{
  "took": 2,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": 2,
    "max_score": 1,
    "hits": [
      {
        "_index": "my_index",
        "_type": "doc",
        "_id": "2",
        "_score": 1,
        "_source": {
          "username": "richard",
          "comment": "Mt favorite movie is Golira!"
        }
      },
      {
        "_index": "my_index",
        "_type": "doc",
        "_id": "1",
        "_score": 1,
        "_source": {
          "username": "harrison",
          "comment": "Mt favorite movie is Star Wars!"
        }
      }
    ]
  }
}

이제 슬레이브를 가동하고 조회해보자. 실제로 슬레이브를 조회해도 동일한 결과가 나오는 것을 확인할 수 있다.

curl -XGET "http://localhost:9201/my_index/_search"  

간단히 엘라스틱서치에서 분산처리를 해보았다. 생각보다 어렵지 않고 쉽게 구현이 되었다. 그런데 실제 분리된 서버에서 적용하려면 슬레이브 elasticsearch.yml에는 discovery.zen.ping.unicast.hosts: 에 마스터 ip 정보를 세팅해야 한다.