Elasticsearch River の配置カスタマイズとサーバー構成

データをフィードする為の River を単独サーバーで動かすためのメモ

Kunihiko Kido
Hello! Elasticsearch.

--

River は、WebコンテンツやTwitter ストリーム、リレーショナルDBなど外部のリソースからデータを Elasticsearch クラスター内に取り込む為の機能(プロセス)のため、単独のサーバーで動かせないか調べてみました。

実現したいサーバー構成は以下の図のようなイメージです。

実現したいサーバー構成

主に、サーチやインデックスを担うサーバー群(Search & Index Servers)と、リバーを稼働させるサーバー群(River Servers)を明示的に分けることで、Search & Index Servers の各サーバーのサーバーリソースの使用を平準化するのが目的です。(例えばリバーがフル稼働しているサーバーに検索に行ったら遅くなるなどの弊害を回避したいなどの要件)

ちなみに River は作成した River 毎に、1つのノード(サーバー)に自動的に起動される仕組みです。また、そのノードが停止された場合には、他のノードへ自動的に起動します。

River の配置ノードをコントロールする

上記サーバー構成を実現するには、まずRiverの配置されるノードをコントロールする必要があります。

調べてみるとちゃんと用意されていました(river » cluster allocation)。node.river オプションを使用することでコントロールできるようです。まず、 River を起動させたくない場合には、_none_ を設定するとそのノードではRiverは起動しなくなります。カンマ区切りで、River のタイプまたは、River の名前を列挙することで起動したいRiverを明示的に指定することが出来ます。

設定方法:

Search & Index Server の elasticsearch.yml に次のプロパティを追加します。

node.river: _none_

または、Search & Index Servers 起動時に次のプロパティを追加して起動します。

$ bin/elasticsearch -Des.node.river=_none_

NOTE: バージョン1.0以降は、コマンド起動時の -Des. プレフィックスなしに指定できるようです。—node.river=_none_ こんな感じ。
reference [1.x] » breaking changes in 1.0 » system and settings

確認方法:

ローカルに2つのElasticsearchを起動します。わかり易くする為に、node.name プロパティでそれぞれのサーバーに名前を付けています。また、以下の ”Search Server” にのみ上記の設定をしています。

$ curl 'localhost:9200/_cat/nodes?h=name,master,ip,port'
River Server m 192.168.1.128 9301
Search Server * 192.168.1.128 9300

テスト用の dummy リバーを使って、次のコマンドで3つのリバーを作成します。

$ curl -XPUT 'localhost:9200/_river/my_river1/_meta' -d '{
"type" : "dummy"
}'
$ curl -XPUT 'localhost:9200/_river/my_river2/_meta' -d '{
"type" : "dummy"
}'
$ curl -XPUT 'localhost:9200/_river/my_river3/_meta' -d '{
"type" : "dummy"
}'

次のコマンドで、それぞのリバーが起動しているサーバーを確認します。

$ curl 'localhost:9200/_river/my_river1/_status' -s|jq '._source.node.name'
"River Server"
$ curl 'localhost:9200/_river/my_river2/_status' -s|jq '._source.node.name'
"River Server"
$ curl 'localhost:9200/_river/my_river3/_status' -s|jq '._source.node.name'
"River Server"

おおっ!すべて、River Server で起動してますね。

TIPS:_status の出力をわかり易くする為に、jq コマンドラインを使用しています。ここからインストール出来ます。

ちなみに、”Search Server” のみ起動してリバーを作成すると、作成は成功しますが起動はしません。その後、”River Server” を起動したタイミングで、作成したリバーが起動します。

Shard の配置ノードをコントロールする

次に、River が起動するサーバーには、サーチとかインデックスの処理は必要ありませんので、Shard が配置されないように、Shard の配置されるノードをコントロールする必要があります。

Shard の配置方法はインデックスレベル、クラスタレベル、ノード毎のシャード数、ディスク使用率によるコントロールなどいろいろあります。今回は、cluster.routing.allocation.exclude.* プロパティを使用して今回の要件を実現しました。

NOTE:cluster.routing.allocation.enable: none の設定もためしてみましたが、この設定はREST API で呼び出したときのみ有効で、さらにノードの指定は出来ないので、cluster.routing.allocation.exclude.* を使用しています。

設定方法:

River Servers の elasticsearch.yml に次のプロパティを追加します。

node.server_group: river
cluster.routing.allocation.exclude.server_group: river

次に、Search & Index Servers の elasticsearch.yml に次のプロパティを追加します。

node.server_group: search
cluster.routing.allocation.exclude.server_group: river

※ node.server_group: search は使用していないため、無くてもOKです。明示的に区別するためだけに記述しています。

NOTE:ノードを識別する為の node.xxx プロパティは任意の名前が使用できます。今回は server_group と言う名前を使ってリバーサーバーの識別に使用しています。

確認方法:

Shard 配置可能な Search サーバー2台と、River サーバー1台の合計3台を以下のように起動しました。わかり易くする為に、node.name プロパティでそれぞれのサーバーに名前を付けています。

$ curl 'localhost:9200/_cat/nodes?h=name,master,ip,port'
River m 192.168.1.128 9301
Search2 m 192.168.1.128 9302
Search1 * 192.168.1.128 9300

次に、適当にインデックスを作成して、Shard の配置状況を次のコマンドで確認します。

$ curl 'localhost:9200/_cat/shards'
twitter 4 r STARTED 0 79b 192.168.1.128 Search2
twitter 4 p STARTED 0 79b 192.168.1.128 Search1
twitter 0 r STARTED 0 79b 192.168.1.128 Search2
twitter 0 p STARTED 0 79b 192.168.1.128 Search1
twitter 3 r STARTED 0 79b 192.168.1.128 Search2
twitter 3 p STARTED 0 99b 192.168.1.128 Search1
twitter 1 r STARTED 0 79b 192.168.1.128 Search2
twitter 1 p STARTED 0 99b 192.168.1.128 Search1
twitter 2 r STARTED 1 2.6kb 192.168.1.128 Search2
twitter 2 p STARTED 1 2.7kb 192.168.1.128 Search1

すばらしい!Search1 と Search 2 のサーバーのみ Shard が割り当てられているのが確認できました。

まとめ

以上の設定で今回の要件は満たせそうです。ただ、作成した1つのリバーはサーバーを増やしてもスケール出来なそうなので、作成する単位を工夫して複数起動するか、サーバーのスペックを上げるなどの対応は必要そうです。

--

--