Elasticsearch5系 クラスタ構成構築手順

## 概要
Elasticsearch5.6のクラスタ環境を構築します。
AWS EC2インスタンスで構築しました。

## 環境
- CentOS 7.2
- elasticsearch 5.6.3-1
- openjdk version "1.8.0_144"
- OpenJDK Runtime Environment (build 1.8.0_144-b01)
- OpenJDK 64-Bit Server VM (build 25.144-b01, mixed mode)


## AWS EC2インスタンスタイプ
- t2.micro

## nodes
以下の3台でクラスタを構築します。

| node | ipaddr |
| --- | --- |
| node-1 | 192.168.131.121 |
| node-2 | 192.168.131.216 |
| node-3 | 192.168.131.195 |


## Elasticsearchのインストール
以下の手順を参考に、3台全てにElasticsearchをインストールしてください。
以下の手順の中にもありますが、t2.microを使用する場合、メモリの使用量の設定変更が必要になるので、併せて設定してください。
[Elasticsearchのインストール手順と簡単な使い方](https://qiita.com/Esfahan/items/963225cd2d2b6b219c05)

## クラスタの設定
以下の設定を3台ともに適用します。
3台とも、同じ`cluster.name`にするだけで、クラスタ構成になります。

```diff
$ vi /etc/elasticsearch/elasticsearch.yml

# 17行目：クラスタ名
-#cluster.name: my-application
+cluster.name: sample-application

# 23行目：node名それぞれ、node-1, node-2, node-3のように別名を付ける
-#node.name: node-1
+node.name: node-1

# 55行目：listenするhost
-#network.host: 192.168.0.1
+network.host: 0.0.0.0

# 68行目：コメント解除して変更 (全ノードを指定する)
-#discovery.zen.ping.unicast.hosts: ["host1", "host2"]
+discovery.zen.ping.unicast.hosts: ["192.168.131.121 ", "192.168.131.216", "192.168.131.195"]

# 72行目：下記参照[(Master Eligible Node 数) / 2 + 1]
-#discovery.zen.minimum_master_nodes: 3
+discovery.zen.minimum_master_nodes: 2
```

- `discovery.zen.minimum_master_nodes` Master (eligible) nodeについて
   - スプリットブレイン対策のために、マスターノードを選ぶ際に必要となる接続ノードの数をノード数/2+1に設定する。
   - 例えば6台構成の場合は4になる。今回は3台なので、3/2 + 1 = 2
   - Master eligible node は master に候補になるノード
   - Master node が死んだときには master eligible node から新たな master が選ばれる
   - 参考：http://kakakazuma.hatenablog.com/entry/2016/07/19/100000_2
   - [クラスタ関連](https://qiita.com/uzresk/items/e0b10c14875b79c450f2#%E3%82%AF%E3%83%A9%E3%82%B9%E3%82%BF%E9%96%A2%E9%80%A3)

引用元：https://gist.github.com/yano3/3f5abc9eba0c1ad6a0508056961b273c#node


#### もしvagrantでクラスタ構築をしている場合の注意点
- network.hostについて
    - vagrantでは、eth1がnicになるため、network.hostで指定する必要がある
    - Elasticsearchはeth0のIPアドレスをデフォルトで指定するようなので、eth1を使うように指定するため、`_eth1:ipv4_`とする
    - vagrantでない場合は、`network.host: 0.0.0.0`などとして、接続許可設定をする

参考：[ネットワークホストの設定](https://qiita.com/uzresk/items/e0b10c14875b79c450f2#%E3%83%8D%E3%83%83%E3%83%88%E3%83%AF%E3%83%BC%E3%82%AF%E3%83%9B%E3%82%B9%E3%83%88%E3%81%AE%E8%A8%AD%E5%AE%9A)

### elasticsearchを再起動

```
$ sudo systemctl restart elasticsearch
```

## 9200/tcp、9300/tcpポートの解放
もしfirewallが起動している場合は、以下のコマンドでポートを開けてください。
また、EC2を使っている場合は、セキュリティグループでポートを開けてください。

9200は、REST APIのポートとして使用され、9300は、node間の連携に使用されます。
Kibanaもインストールする場合は、5601/tcpも開ける必要があります。

```
$ sudo firewall-cmd --add-port={9200/tcp,9300/tcp} --permanent
$ sudo firewall-cmd --reload 
```

## 接続確認
3台それぞれでクラスタの情報を確認します。
`number_of_nodes`が`3`になっていることが確認できればOKです。

```lang:node-1
$ curl --ipv4 http://192.168.131.121:9200/_cluster/health?pretty
{
  "cluster_name" : "sample-application",
  "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,
  "delayed_unassigned_shards" : 0,
  "number_of_pending_tasks" : 0,
  "number_of_in_flight_fetch" : 0,
  "task_max_waiting_in_queue_millis" : 0,
  "active_shards_percent_as_number" : 100.0
}
```

```lang:node-2
$ curl --ipv4 http://192.168.131.216:9200/_cluster/health?pretty
{
  "cluster_name" : "sample-application",
  "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,
  "delayed_unassigned_shards" : 0,
  "number_of_pending_tasks" : 0,
  "number_of_in_flight_fetch" : 0,
  "task_max_waiting_in_queue_millis" : 0,
  "active_shards_percent_as_number" : 100.0
}
```

```lang:node-3
$ curl --ipv4 http://192.168.131.195:9200/_cluster/health?pretty
{
  "cluster_name" : "sample-application",
  "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,
  "delayed_unassigned_shards" : 0,
  "number_of_pending_tasks" : 0,
  "number_of_in_flight_fetch" : 0,
  "task_max_waiting_in_queue_millis" : 0,
  "active_shards_percent_as_number" : 100.0
}
```

### nodeの確認
以下のコマンドでnodeの確認ができます。
`*`がついているのがmaster nodeです。

```
$ curl --ipv4 http://192.168.131.121:9200/_cat/nodes

192.168.131.195 19 93 0 0.00 0.01 0.05 mdi * node-2
192.168.131.121 23 93 0 0.00 0.01 0.05 mdi - node-1
192.168.131.216 13 93 0 0.00 0.01 0.05 mdi - node-3
```

## master nodeの確認
以下のコマンドでmaster nodeを確認できます。
node-2がmasterになっています。

```
$ curl --ipv4 http://192.168.131.121:9200/_cat/master

1Ii0KKzhTmCs-g5zw96aTg 192.168.131.195 192.168.131.195 node-2
```

## master nodeを変更する
前述の例では、master nodeが自動でnode-2になっていましたが、明示的にmaster nodeをnode-1に設定します。
また、master nodeではデータを保持しない設定にします。

それぞれの/etc/elasticsearch/elasticsearch.ymlに、以下を追記します。

- node-1

```yaml:/etc/elasticsearch/elasticsearch.yml
node.master: true
node.data: false
```

- node-2

```yaml:/etc/elasticsearch/elasticsearch.yml
node.master: false
node.data: true
```


- node-3

```yaml:/etc/elasticsearch/elasticsearch.yml
node.master: false
node.data: true
```


また、`discovery.zen.minimum_master_nodes`に設定されている数と、`master: true`が設定されているサーバーの数が同じになっている必要があります。
ずれているとelasticsearchが立ち上がらなかったり問題が起きます。
今回、`master node: true`に設定したサーバーは1台だけなので、master nodeは1台になりました。
なので、3台とも、/etc/elasticsearch/elasticsearch.ymlの`discovery.zen.minimum_master_nodes`の値を`1`に変更します。

```yaml:/etc/elasticsearch/elasticsearch.yml
iscovery.zen.minimum_master_nodes: 1
```

設定変更したら、3台ともelasticsearchを再起動します。

```
$ sudo systemctl restart elasticsearch
```

再起動後、nodeを確認してみると、node-1がmasterになっていることが確認できます。

```
$ curl --ipv4 http://192.168.131.121:9200/_cat/nodes

192.168.131.216 17 93 72 0.36 0.13 0.12 di - node-3
192.168.131.121 16 92  4 0.16 0.11 0.12 mi * node-1
192.168.131.195 15 93  1 0.00 0.05 0.08 di - node-2
```

```
$ curl --ipv4 http://192.168.131.121:9200/_cat/master

y4JlWH0sRrePewfA_E-fpg 192.168.131.121 192.168.131.121 node-1
```

## Shardについて
インデックスを1つ作成すると、複数のShardが作成されます。
デフォルトでは、5つのPrimary shard、1つのReplica shardが作成されるようになっています。
参考：[shards_amp_replicas](https://www.elastic.co/guide/en/elasticsearch/reference/current/_basic_concepts.html#_shards_amp_replicas)

インデックス作成してみます。

```
$ curl -X PUT "http://192.168.131.121:9200/sample_index"
{"acknowledged":true,"shards_acknowledged":true,"index":"sample_index"}
```

作成されたら、`sample_index`の設定情報を確認してみると、
`number_of_shards`が`5`、`number_of_replicas`が`1`になっていることが確認できます。

```
$ curl --ipv4 http://192.168.131.121:9200/sample_index/_settings

{
    "sample_index": {
        "settings": {
            "index": {
                "creation_date": "1507882089402", 
                "number_of_shards": "5", 
                "number_of_replicas": "1", 
                "uuid": "k4asMd7zSjySjw_Kjr3P8w", 
                "version": {
                    "created": "5060399"
                },
                "provided_name": "sample_index"
            }
        }
    }
}
```

ここで、一度インデックスを削除します。

```
$ curl -s -XDELETE http://192.168.131.121:9200/sample_index
{"acknowledged":true}
```

### インデックス作成時にshardの数を指定する
インデックスごとに、shardの数を指定することができます。
インデックステンプレートを使って設定を変更してみます。

インデックステンプレートとは、インデックスが作成されるタイミングで自動で適用される設定のテンプレート機能のことです。
テンプレートの設定は、インデックスが新規に作成されるときのみ適用されます。
既に作成済のインデックスに対しては反映されません。

まず、以下のコマンドで、設定を変更します。
URLに含まれる、`template_1`が、このテンプレートの名前であり、削除するときにはこの名前を指定します。
また、`"template" : "sample*"`は、頭にsampleという名前がついているインデックスに対してのみ適用するという意味です。


参考：[インデックステンプレートとは](http://blog.johtani.info/blog/2014/11/25/import-apache-accesslog-using-logstash-2/)

```
$ curl -XPUT http://192.168.131.121:9200/_template/template_1 -d '
{
    "template" : "sample*",
    "settings" : {
        "number_of_shards" : 1
    }
}'

{"acknowledged":true}
```

設定を確認します。

```
$ curl -s  http://192.168.131.121:9200/_template/template_1

{
    "template_1": {
        "aliases": {}, 
        "mappings": {}, 
        "order": 0, 
        "settings": {
            "index": {
                "number_of_shards": "1"
            }
        }, 
        "template": "sample*"
    }
}
```

インデックスを作成します。

```
$ curl -X PUT "http://192.168.131.121:9200/sample_index"
{"acknowledged":true,"shards_acknowledged":true,"index":"sample_index"}
```

インデックスの設定情報を確認してみます。


```
$ curl --ipv4 http://192.168.131.121:9200/sample_index/_settings

{
    "sample_index": {
        "settings": {
            "index": {
                "creation_date": "1507889862249", 
                "number_of_shards": "1", 
                "number_of_replicas": "1", 
                "uuid": "YGgw1pp7SWW6fPHB6A0BIg", 
                "version": {
                    "created": "5060399"
                },
                "provided_name": "sample_index"
            }
        }
    }
}
```

`number_of_shards`が`1`に変わっています。これで、設定を変更することができました。
`number_of_replicas`についても、同じように設定変更することができます。

### Primary shard(書き込み可能)
primary shardとは、インデックスを物理的に分割したもののことです。
インデックス作成後には変更することは不可能なので、インデックス作成時に指定します。

### Replica shard(読み取り専用)
Replica shardとは、PrimaryShardを複製したもので、読み取り専用のものです。
primary shardがダウンした場合は、Replica shardがPrimaryに昇格します。
Replica shardの数は、後で変更することが可能です。


参考：[[Elasticsearch]インデックス作成時のシャード数を変更してみる](https://qiita.com/toshihirock/items/4c1ad1c513cbdb02c9ed)

### shardの確認
以下のコマンドで、shardの確認をすることができます。

インデックス名, docsの番号、Primary(p) or Replica(r)、ステータス, document数, サイズ, ipアドレス, node名

```
$ curl --ipv4 http://192.168.131.121:9200/_cat/shards
sample_index 1 p STARTED 0  162b 192.168.131.195 node-2
sample_index 1 r STARTED 0  162b 192.168.131.216 node-3
sample_index 3 p STARTED 1 4.5kb 192.168.131.121 node-1
sample_index 3 r STARTED 1 4.5kb 192.168.131.195 node-2
sample_index 4 r STARTED 0  162b 192.168.131.121 node-1
sample_index 4 p STARTED 0  162b 192.168.131.195 node-2
sample_index 2 r STARTED 0  162b 192.168.131.121 node-1
sample_index 2 p STARTED 0  162b 192.168.131.216 node-3
sample_index 0 p STARTED 0  162b 192.168.131.121 node-1
sample_index 0 r STARTED 0  162b 192.168.131.216 node-3
```

以上

## 関連記事
- [EmbulkでMySQLのデータをElasticsearch5に転送する](https://qiita.com/Esfahan/items/c2a22da5d57bfa1d4cc4)

## 参考
- [Elastic Stack : Elasticsearch クラスターを構成する](https://www.server-world.info/query?os=CentOS_7&p=elasticstack&f=2)
- [Elasticsearch クラスタをマルチノードでインストールする](http://sfujimoto.hatenablog.com/entry/2017/01/08/192418)
- [Elasticsearch導入前に気を付けておきたいこと！](https://qiita.com/uzresk/items/e0b10c14875b79c450f2)
- [Amazon EC2 を使用して Elasticsearch クラスタをセットアップする](https://www.elastic.co/jp/blog/setting-up-es-cluster-on-ec2)
- [Elasticsearch用語の適当なまとめ](https://qiita.com/ise_daisuke/items/5e10e0b3ef9dffed08a9)
- [第６回 Elasticsearch 入門 基本コンセプトを理解する](https://dev.classmethod.jp/server-side/elasticsearch-getting-started-06/)
- [Elasticsearch API 一覧](https://medium.com/hello-elasticsearch/elasticsearch-api-83760ce1424b)
- [localhostのelasticsearchにcurlしたらConnection Refused](http://jangajan.com/blog/2014/12/16/fail-to-curl-to-elasticsearch/)