読者です 読者をやめる 読者になる 読者になる

notebook

都内でWEB系エンジニアやってます。

elasticsearch シャードとか、インデックスとか

運用で使いそうなコマンドとか

インデックス操作

インデックス一覧

インデックス一覧を取得する

pretty で見やすく改行してくれる

curl -XGET http://localhost:9200/_aliases?pretty

curatorを使ったほ方が楽に確認できる

  • monitorで始まるインデックス全てを確認する
curator --host 192.168.20.20 show indices --prefix monitor

簡単なデータの登録

とりあえずなにか突っ込んでみる

# curl -XPOST http://{host}:{port}/{index名}/{type名}/{id} -d 'json data'
curl -XPOST http://192.168.20.20:9200/test/testname/1 -d '{"first":"first","second":"second", "number": "100"}'

elasticsearch-headとかでシャードができたか確認してみる

f:id:swfz:20150722040152p:plain

インデックスの削除

logstash-2015-03-20のインデックスを削除する

データ量が多くなると重くなったりするようなので定期的な削除が必要

curlで叩く場合は以下

  • 「logstash-2015-03-20」というインデックスを削除
curl -XDELETE http://localhost:9200/logstash-2015-03-20

シャードの操作

シャードの確認

インデックスとかプライマリシャードか否か、さまざまな情報が取得できる

インデックス名,docsの番号、プライマリ(p)かレプリカ(r)か、ステータス,document数,サイズ,ip,node名

$ curl -XGET 'http://192.168.20.18:9200/_cat/shards'
monitor.ip-10-0-21-30.dstat-2015-06-09        2 p STARTED    182  316.2kb 127.0.0.1 node2261
monitor.ip-10-0-21-30.dstat-2015-06-09        2 r STARTED    182  316.2kb 127.0.0.1 node2161
monitor.ip-10-0-21-30.dstat-2015-06-09        0 p STARTED    172  292.4kb 127.0.0.1 node2260
monitor.ip-10-0-21-30.dstat-2015-06-09        4 p STARTED    165  279.5kb 127.0.0.1 node2161
backend.debug_log-2015-06-09                  3 r STARTED  19330    3.5mb 127.0.0.1 node2161
backend.debug_log-2015-06-09                  1 p STARTED  19309    3.5mb 127.0.0.1 node2260

ノード毎のドキュメント数を出したり、これ見ながらメンテのときとか対象ノードにデータがなくなったかどうかチェックしたりできる

$ curl -s -XGET http://192.168.20.18:9200/_cat/shards | awk '{print $8}' | sort  | uniq -c
   2420 node2161
   2421 node2260
   2421 node2261

APIに関しては下記サイトに詳しく載っているので見に行くのが一番早いと思います

Elasticsearch API一覧

シャードの再配置

unassignedとかになっていた場合にインデックスを再配置する

先ほどのcat apiで情報を取得して対象のシャードの情報を入れ込む

curl -XPOST 'http://192.168.20.18:9200/_cluster/reroute' -d '{
  "commands": [{
    "allocate": {
      "index": "monitor.192-168-20-20.dstat-2015-04-28",
      "shard": 1,
      "node": "node2261",
      "allow_primary": true
    }
  }]
}'

シャードの移動

  • 再配置とは若干異なり、from,toが必要
curl -XPOST 'http://192.168.20.18:9200/_cluster/reroute' -d '{
  "commands": [{
    "move": {
      "index": "monitor.192-168-20-20.dstat-2015-04-28",
      "shard": 1,
      "from_node": "node2261",
      "to_node": "node2260"
    }
  }]
}'

ノードのシャード配置設定

メンテの時など、ひとつのノードを空にして一旦止めて作業したいときとか、上記のAPIを使用してシャードを移動してもelasticsearch側で自動再配置してくれる機能があるので戻されてしまう

そこで、下記コマンドで特定ノードに対してシャードの再配置を防止する

curl -XPUT http://192.168.20.20:9200/_cluster/settings -d '{
  "transient": {
    "cluster.routing.allocation.exclude._name": "node_name"
  }
}'
  • shardの割り当てを確認
curl -s -XGET http://192.168.20.20:9200/_cat/shards | grep 'node_name' | wc -l

headで確認するとこんな感じ

f:id:swfz:20150722040210p:plain

  • 復帰
curl -XPUT http://192.168.20.20:9200/_cluster/settings -d '{
  "transient": {
    "cluster.routing.allocation.include._name": "node_name"
  }
}'

2015-11-18 追記

てっきり↑で行けたと思っていたのですが実は違ったようです

クラスタのセッティングを見るAPIを叩いてみると下記のようになっていて、実際は設定が残ったままになっていました

curl -s -XGET http://192.168.20.20:9200//_cluster/settings | jq
{
  "persistent": {},
  "transient": {
    "cluster": {
      "routing": {
        "allocation": {
          "include": {
            "_name": "node_name"
          },
          "exclude": {
            "_name": "node_name"
          }
        }
      }
    }
  }
}

なので設定されているものを空に設定しなおしてあげる事で対処しました。

この方法が正しいのか自信はありませんが、シャードの再配置が行われている事を確認しました。

curl -XPUT http://192.168.20.20:9200/_cluster/settings -d '{
  "transient": {
    "cluster.routing.allocation.exclude._name": ""
  }
}'
curl -XPUT http://192.168.20.20:9200/_cluster/settings -d '{
  "transient": {
    "cluster.routing.allocation.include._name": ""
  }
}'

関係なさそうだけどincludeも一旦空に

curl -s -XGET http://192.168.20.20:9200//_cluster/settings | jq
{
  "persistent": {},
  "transient": {
    "cluster": {
      "routing": {
        "allocation": {
          "include": {
            "_name": ""
          },
          "exclude": {
            "_name": ""
          }
        }
      }
    }
  }
}

2015-11-18 追記ここまで

query

elasticsearchはlucene queryというものを使って問い合わせしている

単純にjsonを投げれば結果が返ってくる

inquisitor pluginとか使って試すと理解しやすいかもしれない

elasticsearch-inquisitor

色々と投げる方法があるみたいだがあまり詳しくは調べてないのでまた後日....

基本的に「query」の中で問い合わせたいクエリを記述する

elasticsearchがRESTAPIを使うことができるのでajaxとか使って生ログ検索とかなら割と簡単に実装できる

それだけでもログ出してっていう調査は減るはず! 自分で調べられるよね♪

  • urlフィールドに「tete」という文字が含まれているものを取得
{
  "query" : {
    "query_string" : {
       "query": "url: /.*tete.*/"
    }
  }
}
  • highlight

検索結果をハイライトしてくれる機能

フィールドによってタグを変えたりとかもできるようで結構便利そう

{
  "query" : {
    "query_string" : {
       "query": "url: /.*tete.*/"
    }
  },
  "highlight": {
    "fields": { "url": {} },
    "pre_tags": [ "<b>" ],
    "post_tags": [ "</b>" ]
  }
}

マッピングテンプレート

elasticsearchはデータを受け取った時に自動的に型を決めてくれますが、想定と違う場合などがある

templateという仕組みを使ってあらかじめフィールドのデータの型やマッピングなどを定義することができる

方法としては、RESTAPIで行うかファイルを用意するかの2通り

dynamic mapping

/etc/elasticsearch/templates 以下に定義したjsonファイルを配置する

そうするとelasticsearchが勝手に読みこんでくれてインデックスを新たに作る際に設定を反映してくれます

特に再起動などもいらないよう

今回は完全一致での検索をやりたかったのでmulti_fieldsでanalyzedとnot_analyzedの両方のカラム(.full)を生成するように

参考サイトのマルコピだけど。。。w

f:id:swfz:20150722040223p:plain

not_analyzedにすることで全文検索が可能になるので上記のような警告がなくなる

これでkibanaで.fullに対してユニークカウントを取ることができるようになる

─
{
  "template": "*",
  "mappings": {
    "_default_": {
      "dynamic_templates": [
      {
        "string_template": {
          "match": "*",
          "mapping": {
            "type": "multi_field",
            "fields": {
              "{name}": {
                "type": "string",
                "index": "analyzed"
              },
              "full": {
                "type": "string",
                "index": "not_analyzed"
              }
            }
          },
          "match_mapping_type": "string"
        }
      }
      ],
      "properties": {
        "@timestamp" : { "type" : "date", "index" : "not_analyzed" }
      }
    }
  }
}

定義しなかったものは今まで通り自動で型を推測してインデックスを作成してくれます

  • 確認
curl -XGET "localhost:9200/_template/sample_template?pretty"
curl -XGET http://192.168.20.41:9200/index_name/_mapping?pretty=true

Kibana+Elasticsearchで文字列の完全一致と部分一致検索の両方を実現する

curator

このツールだと「何日以前のこのインデックスは全て削除する」というようにインデックスに対する操作を簡単に行えるようになる

インストール

yum install python-setuptools
# Amazon Linuxの場合下記二つ依存モジュールあり、CentOS6の場合、pbrのみ必要,デフォルトで使ってるpythonがpython3だと特に依存モジュールなかった
# easy_install six==1.4
# easy_install pbr
easy_install elasticsearch-curator

実行

良く紹介されるのはインデックスの削除だがインデックスの削除以外にも色々ある模様

suffix,prefixオプションなどあるので汎用的に使えそう

これをcronなりなんなりで運用すればローテーションみたいなことができる

いきなり削除は怖い、とか、後で見たかった!と言われたときに対応できるようにcloseというのもあります

closeしたインデックスに関しては検索対象には入らないがデータとしてはあるというような状態なので余計なリソースは消費しないという感じのもの

また、openで検索対象に戻すことができる

  • delete
  • 「forward」で始まるインデックスについて、30日以前のインデックスを全て削除する
curator --host 192.168.20.18  delete indices --prefix forward --older-than 30 --time-unit days --timestring %Y-%m-%d
  • インデックス指定で削除する
curator --host 192.168.20.18 delete indices --index error_log-2015-05-31
  • close
curator --host 192.168.20.18  close indices --prefix forward --older-than 30 --time-unit days --timestring %Y-%m-%d

インデックスの指定方法は下記を見れば大体分かると思います

Index Selection

クラスタ名について

  • データはデフォルトだと/var/lib/elasticsearch/以下に保存される
    • CentOS6の場合、/etc/sysconfig/elasticsearchで修正可能

/var/lib/elasticsearch/{cluster.name}/nodes というように保存されるためクラスタの名前を変えるとデータが消えたように見える

テスト環境でクラスタ名変えて再起動したらディレクトリ入れ替えても元に戻しても動かなくなってしまった、、、

むやみにクラスタ名は変えない方がいいということですねw

また、ログファイルもクラスタ名をログファイル名とするようになっているのでログファイル名も変わる

ログを監視とかしてたら気を付ける必要がありますね

参考:

dynamic mapping

Index Selection

Index Templates

elasticsearch-inquisitor

プロダクション環境でElasticsearch+kibana(fluentd)でログ可視化運用をしてみてわかった事

Kibana+Elasticsearchで文字列の完全一致と部分一致検索の両方を実現する

ElasticSearch テンプレートでインデックスの型を指定する

Elasticsearch API一覧