すずけんメモ

技術メモです

複数のインデックスをまとめて消す方法

Delete Index http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/indices-delete-index.html

にも書いてあるけど、*が使える。単一のインデックスを消す場合には以下のようにする。

$ curl -XDELETE 'http://localhost:9200/twitter/'

もし、hoge1hoge2fuga1というインデックスがあって、hoge1hoge2だけ消したい場合には以下のようにする。

$ curl -XDELETE 'http://localhost:9200/hoge*/'

Elasticsearchのクラスタにノードを追加するときにやっていること

Elasticsearchのクラスタにノードを追加するのは簡単にできる。しかし、インデックスを盛々積んだクラスタにノードをカジュアルに追加すると、一気にシャードのアロケーションが走って負荷があがる。また、何の設定もせずに追加するとsplit brainを起こしやすくなる。適切に設定すれば大丈夫なので、それをまとめておく。

結論

安全にやるなら、

  • ノード追加前に全shardの移動を止める。
  • split brainを避けるために、最小のマスターノード数を設定しておく。

ということをしておくとよい。

クラスタ設定はリアルタイムに変更できるので活用しよう。

Cluster Update Settings http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/cluster-update-settings.html

ノード追加前の準備

シャードの移動をとめておく。また、最小のマスターノード数を普段よりちょっと多めに設定しておく。こうしておけばsplit brainを防げる。なお、discovery.zen.minimum_master_nodesの設定はノード数 / 2 + 1にしておく。ノードを追加するときは追加したあとのノード数に合わせて設定しておくとよい。

例えば、3ノードのクラスタに2ノード追加するとする。その場合、discovery.zen.minimum_master_nodes5 / 2 + 1 = 3.5なので、3か4にしておく。

$ curl -XPUT http://es1:9200/_cluster/settings -d '{
"persistent": {"cluster.routing.allocation.enable": "none"}
}'
{"acknowledged":true,"persistent":{"cluster":{"routing":{"allocation":{"enable":"none"}}}},"transient":{}}%

$ curl -XPUT http://es1:9200/_cluster/settings -d '{
"persistent": {"discovery.zen.minimum_master_nodes": 3}
}'
{"acknowledged":true,"persistent":{"discovery":{"zen":{"minimum_master_nodes":"3"}}},"transient":{}}%

実際にノードを追加する。ノードを追加した際にclusterに追加されている様子はelasticsearch-headなどでみるのがよい。

mobz/elasticsearch-head https://github.com/mobz/elasticsearch-head

split brainしていないか観察しておく。もしsplit brainしてしまったら、discoveryをもう一度走らせる必要があるので気をつけよう。

無事ノードがクラスタに追加されたことを確認したら、シャード移動を許可するようにする。

$ curl -XPUT http://es1:9200/_cluster/settings -d '{
"persistent": {"cluster.routing.allocation.enable": "all"}
}'
{"acknowledged":true,"persistent":{"cluster":{"routing":{"allocation":{"enable":"none"}}}},"transient":{}}%

するとシャードが各ノードに移っていくことが確認できる。なお、デフォルトだと1インデックスにつき2シャードずつしか移動が行われないようになっている。cluster.routing.allocation.cluster_concurrent_rebalanceを調整することでこれを変更することもできる。1インデックスあたりのシャード数を多めに設定している場合には、この設定を増やすことによって、シャードの移動を早くすることができる。ただし、当然シャード移動のためのトラフィックも増えるので、そこはモニタリングしつつ行うようにする。

Cluster http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/modules-cluster.html

他にも、もしDCが分かれているなどの場合にはそれぞれのrackごとに設定をすることもできる。

write heavyなときの設定

あんまりクエリされないけど、書き込みがめっちゃ多い運用というのもあると思う。今うちで使ってる方法だと、限られた人たちがKibanaでクエリするので、多くても2桁人。

  • 書き込みはスムーズにしたい
  • 検索は多少遅くてもいいけど確実に結果が帰ってきてほしい
  • STWは避けたい

ということで最近いろいろ調査してた。

ElasticSearch config for a write-heavy cluster https://gist.github.com/reyjrar/4364063

上記の設定は割りと参考になりそうなので、来週の検証に利用してみる。

Elasticsearch 1.x系統でのgatewayに関して

Localのみ推奨、となっている。

Gatewayモジュールというのがあって、

端的にいうとクラスタ管理のためのメタデータを保持する部分になっている。デフォルトではlocalに保存するようになってる。

弊社ではAWSでElasticsearchを運用しているのでS3 Gatewayを検討しよう、と思ったらどうもdeprecateになっているらしい。

ちなみにこのへんのissueで議論されている。

shared gatewayについては基本的に廃止の方向のようだ。

ちなみにAWSがらみでいうと、Elasticsearchへのautoscaling適用についてはこのへんで議論されている。

自分ところの環境では当面Elasticsearchのautoscaling運用は考えてない。少なくとも現時点では。理由はシンプルで、ノード追加のタイミングでのshardのreplicationの負荷がどうしても発生するので、そのへんrerouteをしっかり設定して、、、となると結局autoscaling groupごとにrouteを考えよう、などなど考える部分が増えるので。ひとまずトラフィックが予測できるならautoscalingにしなくてもよいのでは、と思っている。

update

2014/03/27 16:10 Local Gateway以外、削除されました。Elasticsearch 1.2.0から反映されるようです。

参考: Remove deprecated Gateways · Issue #5422 · elasticsearch/elasticsearch https://github.com/elasticsearch/elasticsearch/issues/5422

Elasticsearch 1.0.1でcuratorが動かない場合

現象が報告されているようです。

Master branch doesn't work with Elasticsearch 1.0.1 · Issue #56 · elasticsearch/curator https://github.com/elasticsearch/curator/issues/56

curatorのmasterブランチでは対応しているようなので、現段階での対応としてはpipでmasterブランチからいれるようにしましょう。

$ pip install https://github.com/elasticsearch/curator/tarball/master

これでうちの環境では動くようになりました。

update

2014/03/27 13:15 pipへのリリースもされ、通常通りpip install elasticsearch-curatorで動作するようになりました。

preferenceを利用してsearchを特定シャードでのみ実行する

Preference http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-request-preference.html

これを使う。

例えば、primary shardでのみ実行してみる。

GET _search?preference=_primary
{
    "facets":{
        "terms": {
            "terms": {
                "field": "_type",
                "size": 10,
                "order":"count"
            }
        }
    }
}

通常は?

primary shard, replica shardをランダムに利用するようになっている。クエリの実行結果の_shardsをみるとどのシャードで実行されたのかを確かめることができる。

Vagrant環境にpuppetを利用してさくっとelasticsearchのclusterを作成する

cluster構成をつくってみる。結論から言うと、

  • ちゃんとnetwork.hostVMに設定する
  • すると勝手にmulticastでnodeが発見される

以下の記事と同様にelasticsearch用のノードをもう1つ作る。

NodeのディスカバリにはZen Discoveryを利用する。単純にマルチキャストを利用すればよいだろう。と思ったらエラー。どうやらnetwork.hostをちゃんと設定しなければならないらしい。

結論、というか設定

以下のように設定する。

Vagrantfile

# -*- mode: ruby -*-
# vi: set ft=ruby :

Vagrant.configure("2") do |config|
  config.vm.box = "centos64"
  config.vm.box_url = "http://puppet-vagrant-boxes.puppetlabs.com/centos-64-x64-vbox4210.box"

  config.vm.define :search01 do |search_config|
      search_config.vm.hostname = "search01.local"
      search_config.vm.network "private_network", ip: "192.168.10.114"
  end

  config.vm.define :search02 do |search_config|
      search_config.vm.hostname = "search02.local"
      search_config.vm.network "private_network", ip: "192.168.10.115"
  end

manifests/search.pp

include search

ついでにelasticsearch-headとMarvel, elastic-HQもいれてある。

roles/search/manifests/init.pp

class search {
  service { 'iptables':
    enable => false,
    ensure => stopped,
  }

  class { 'elasticsearch':
    package_url => 'https://download.elasticsearch.org/elasticsearch/elasticsearch/elasticsearch-0.90.11.noarch.rpm',
    java_install => true,
    config => {
      'cluster' => {
        'name' => 'test-es-cluster01'
      },
      'network.host' => '_eth1:ipv4_',
      'marvel.agent.exporter.es.hosts' => ['192.168.10.114:9200','192.168.10.115:9200']
    }
  }

  elasticsearch::plugin{'elasticsearch/marvel/latest':
    module_dir => 'marvel'
  }

  elasticsearch::plugin{'mobz/elasticsearch-head':
    module_dir => 'head'
  }

  elasticsearch::plugin{'royrusso/elasticsearch-HQ':
    module_dir => 'HQ'
  }
}

あとは

$ vagrant up search01
$ vagrant up search02
$ vagrant ssh-config search01 --host search01.local >> ~/.ssh/config
$ vagrant ssh-config search02 --host search02.local >> ~/.ssh/config
$ ssh search01.local "cd /vagrant && sudo puppet module install elasticsearch-elasticsearch"
$ ssh search02.local "cd /vagrant && sudo puppet module install elasticsearch-elasticsearch"
$ ssh search01.local "cd /vagrant && sudo puppet apply --modulepath=/etc/puppet/modules:modules:roles manifests/search.pp"
$ ssh search02.local "cd /vagrant && sudo puppet apply --modulepath=/etc/puppet/modules:modules:roles manifests/search.pp"

とすればVMが2つ立ち上がってelasticsearchのクラスタが組まれる。Marvelでみるとこんな感じ。

f:id:suzu_v:20140205232227p:plain

ついでにもう1つノード足すとこんな感じになる。設定は割愛。単純に同じようにVMつくってmanifestあてれば勝手にclusterに追加される。簡単。

f:id:suzu_v:20140205232320p:plain

中身的なこと

ちなみに各サーバの/etc/elasticsearch/elasticsearch.ymlは以下のようになる。Marvelはデフォルトだとlocalhost:9200をみるようになっているので、明示してあげるようにしている。

### MANAGED BY PUPPET ###
---
cluster:
  name: test-es-cluster01
marvel:
  agent:
    exporter:
      es:
        hosts:
             - 192.168.10.114:9200
             - 192.168.10.115:9200
network:
  host: _eth1:ipv4_

ここ、明示しなくても勝手にノード検出するんじゃないかという気がしているけど、とりあえずこれで。

http://www.elasticsearch.org/guide/en/marvel/current/#stats-export をみると以下のように載っている。

A list of hosts in hostname:port format to which statistics and events will be sent. Data will be sent to the first host, but will failover to the next host(s) if the first is not reachable. Defaults to ["localhost:9200"].

ということなので、複数載せておけば勝手にfailoverして隣のホストにexportするようにしてくれるらしい。便利。

細かいエラーの話

環境によるかもしれないけど、VMで立ち上げたnodeはデフォルトでnetwork.hosteth0を見るようになっている。この場合、例えばunicastでpingしてnodeを検出しようとしてもerrorがでてしまう。この場合、network.host10.0.2.15になっている。

[2014-02-05 07:30:18,350][INFO ][discovery.zen            ] [Rocket Raccoon] failed to send join request to master [[Kismet][QjUBU_iKTc6oLJn-trkEVw][inet[/10.0.2.15:9300]]], reason [org.elasticsearch.transport.RemoteTransportException: [Rocket Raccoon][i
net[/10.0.2.15:9300]][discovery/zen/join]; org.elasticsearch.ElasticSearchIllegalStateException: Node [[Rocket Raccoon][oWubpeP8Q5atLeAIlD2rWA][inet[/10.0.2.15:9300]]] not master for join request from [[Rocket Raccoon][oWubpeP8Q5atLeAIlD2rWA][inet[/10.0.
2.15:9300]]]]

network.hostVMのhostにしてもやっぱりだめ。

[2014-02-05 07:34:24,593][WARN ][discovery.zen            ] [Americop] failed to connect to master [[Kismet][QjUBU_iKTc6oLJn-trkEVw][inet[/10.0.2.15:9300]]], retrying...
org.elasticsearch.transport.ConnectTransportException: [Kismet][inet[/10.0.2.15:9300]] connect_timeout[30s]
        at org.elasticsearch.transport.netty.NettyTransport.connectToChannels(NettyTransport.java:718)
        at org.elasticsearch.transport.netty.NettyTransport.connectToNode(NettyTransport.java:647)
        at org.elasticsearch.transport.netty.NettyTransport.connectToNode(NettyTransport.java:615)
        at org.elasticsearch.transport.TransportService.connectToNode(TransportService.java:129)
        at org.elasticsearch.discovery.zen.ZenDiscovery.innerJoinCluster(ZenDiscovery.java:335)
        at org.elasticsearch.discovery.zen.ZenDiscovery.access$500(ZenDiscovery.java:76)
        at org.elasticsearch.discovery.zen.ZenDiscovery$1.run(ZenDiscovery.java:283)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
        at java.lang.Thread.run(Thread.java:744)
Caused by: java.net.ConnectException: Connection refused: /10.0.2.15:9300
        at sun.nio.ch.SocketChannelImpl.checkConnect(Native Method)
        at sun.nio.ch.SocketChannelImpl.finishConnect(SocketChannelImpl.java:739)
        at org.elasticsearch.common.netty.channel.socket.nio.NioClientBoss.connect(NioClientBoss.java:150)
        at org.elasticsearch.common.netty.channel.socket.nio.NioClientBoss.processSelectedKeys(NioClientBoss.java:105)
        at org.elasticsearch.common.netty.channel.socket.nio.NioClientBoss.process(NioClientBoss.java:79)
        at org.elasticsearch.common.netty.channel.socket.nio.AbstractNioSelector.run(AbstractNioSelector.java:318)
        at org.elasticsearch.common.netty.channel.socket.nio.NioClientBoss.run(NioClientBoss.java:42)
        at org.elasticsearch.common.netty.util.ThreadRenamingRunnable.run(ThreadRenamingRunnable.java:108)
        at org.elasticsearch.common.netty.util.internal.DeadLockProofWorker$1.run(DeadLockProofWorker.java:42)
        ... 3 more

host側ネットワークを見れるようにするためにnetwork.hostを変更すればよかったのでした。 @johtani さんのreplyで気が付きました。ありがとうございました。