初心者が送る！ElasticSearch運用日記

#初心者が送る！ElasticSearch格闘日記

ElasticSearch導入2回目の初心者ですが
日々、ElasticSearchと戦いながら楽しく運用をしています。


##導入してわかったメリット
・可視化することで異変に気づく(気づいてしまうことも。。)
・時系列にすることで思わぬ気づきがある
・ログ調査のスピード早くなる


##日々の格闘
新規システム構築時にあわせ、
可視化目的で運用(監視)ツールの一環としての構築。
導入の際、投入するログ量が多いと分かっていたのですが、
負荷と戦う毎日を繰り返しています！！


##稼働環境  
・ElasticSearch 1.4.4
・kibana 4
・AWS t2.large×8台 EBS:250G
・ES_HEAP_SIZE：4096m
・3000～6000docs/秒
・データサイズ：600GB程度
・index数：500個位
 



##定期的なindexのお掃除
Cronで定期的にindexの削除を実施しており
以下のようなスクリプトを実行

```
TGTDATE=$1
URL="http://xxxx:9200"
curl -s ${URL}/_cat/indices 2>/dev/null | awk -v TGTDATE=$TGTDATE '$3 ~ TGTDATE { print $3 }' | \
while read INDEX
do
  curl -s -XDELETE -w'\n' ${URL}/${INDEX} | jq .acknowledged
done
```


考慮点として、直近のデータ以外は必要ではないため、
indexの保持期間は2日保存と自分ルールを決めてます。


##インデックス命名規則
Fluentdでfluent-plugin-elasticsearchからデータ投入。

2つのパターンで分けており

1. Webサーバなどのデータ量が大きいもの
2. OSのログなど負荷が低いもの

でインデックス命名規則を分けています。

1時間単位のネーミング

```td-agent.conf
    <template>
      include_tag_key true
      tag_key @log_name
      host xxxxxx
      port 9200
      logstash_format true
      logstash_prefix ${tag_parts[0]}
      logstash_dateformat  %Y.%m.%d-%H

      buffer_chunk_limit 16m
      buffer_queue_limit 256

      buffer_type file
      buffer_path /var/log/td-agent/buffer1/elastic_${tag}
      flush_at_shutdown true

      flush_interval 1s
      try_flush_interval 2s
      queued_chunk_flush_interval 1s

      num_threads 4
      retry_limit 2
      retry_wait 2
    </template>
```

日単位のindex

```td-agent.conf
  <template>
    include_tag_key true
    tag_key @log_name
    host xxxxx
    port 9200
    logstash_format true
    logstash_prefix ${tag_parts[1]}
    logstash_dateformat  %Y.%m.%d

    buffer_chunk_limit 8m
    buffer_queue_limit 128
    buffer_type file
    buffer_path /var/log/td-agent/buffer2/elastic_${tag}
    flush_at_shutdown true

    flush_interval 1s
    try_flush_interval 2s
    queued_chunk_flush_interval 1s

    num_threads 4
    retry_limit 2
    retry_wait 2
  </template>
```

ただ、1時間単位でindexを作ること数が多くなり運用しずらいです。


#送り先であるFluentdのチューニング
Fluentdを使ってElasticSearchのですが、
NGINXなどのログは大量に送られてくるので
データ送信を設定値で細かくしています

大きい値8と小さい値0.01くらいまで
パフォーマンスを取って試しましたが、この環境では

```td-agent.conf
      flush_interval 1s
      try_flush_interval 2s
      queued_chunk_flush_interval 1s
```

が良かった結果でした



#負荷軽減のためのIndexTemplate

fieldのtypeで考慮している点

なるべく負荷を下げようとした結果、
・集計しないとき

```Index.Template
    "index": "no",
    "doc_values": true,
    "type": "string"
```


・本当にkibanaとかで集計するとき  


```Index.Template
    "index": "not_analyzed",
    "doc_values": true,
    "type": "string"
```

を設定しています。

基本的には、"index": "no"を設定しておき
どうしてもKibanにグラフ化したいときには
"index": "noを設定しないような運用をしています。  
  
あわせて、refresh_intervalに30秒を指定して付加を軽減しています。

```elasticsearch.yml
    "index.refresh_interval": "30s",
    "index.number_of_replicas": "1
```

#データの長期保存のための再集計
2日でデータを削除するとしても、長期保存したいデータもあり
その場合は、保存したいデータを集計して抜き出し、再度ElasticSearchに入れ込んで
工夫しています。

再投入の際には、複数値で割り算など求めて加工したり
他にも、zabbixとかAeroSpikeのデータなどAPIで取って
ElasticSearchに含めて集約しています。


#設定値
node名にホスト名を入れたいので

```elasticsearch.yml
    node.name: ${HOSTNAME}
```

を指定して、

```/etc/init.d/elasticsearch
    export HOSTNAME=ES-SERVER
```
とホスト名で認識されるようにしています。


リバランシンシングで均等にするため
 cluster.routing.allocation.cluster_concurrent_rebalance
や
リカバリー時に負荷を少なくするため
 cluster.routing.allocation.node_concurrent_recoveries: 3
 indices.recovery.max_bytes_per_sec: 50mb
 indices.recovery.concurrent_streams: 5
をいれています。


##EC2のインスタンス入れ替え
導入当初はc4.large×8台を使っていたが
コストの兼ね合いもあり、t2.largeへ移行しました。

移行方法はこちらを参考にしました
https://www.elastic.co/guide/en/elasticsearch/guide/current/_rolling_restarts.html


#Kibanaのデータバックアップ
Kibana再設定は手間がかかるのでデータバックは重要です！
elasticsearch-cloud-awsを使っているので、S3に時々保存しています。
https://github.com/elastic/elasticsearch-cloud-aws#s3-repository
https://www.elastic.co/guide/en/elasticsearch/reference/current/modules-snapshots.html


#障害対応時
残念ながら、負荷に負けてしまうことが時々あります。
そんなときは、復旧ができなくなるため、断腸の思いでindex削除しています。

```
curl -XDELETE 0:9200/*2015*
```

でindex削除しています。
ですので、長期保存用のindexなど必要なデータはindex名を変えておきます。


あとは、
unassigned_shardsが無いかCronで定期チェックしていたり、
unassigned_shardsがあった場合は

```
  curl -s -m 5 -XPOST '0:9200/_cluster/reroute' -d '{
    "commands" : [ {
          "allocate" : {
              "index" : "'$index名'",
              "shard" : '$shard',
              "node" : "'$割当先'",
              "allow_primary" : true
          }
        }
     ]
  }' | jq -r .acknowledged
```
で配置しているようにしています。


##最後に
AZ間を跨いで稼動させているので通信量が気になって、ノード間の通信量を調べたてみたかったり
スプリットブレインがおきたときの対処を冷静にしたり
EC2のインスタンスストアを使えばよかったと思ったり
これからも日々楽しく運用してみます。