背景
Elasticsearch を本格的に使い始めた頃は、クラスタが安定して動作せず、いつの間にか1ノードが落ちていたり、クラスタ全体のパフォーマンスが低下していたり、悩まされることも多いです。
復旧するために、ノードを再起動することもありますが、ノード起動時にはシャードのリバランシングが行われ、それに多くの時間を要してしまいます。
不用意にノードの再起動を行うと、クラスタの状態が安定するまでに時間を要してしまいます。
こういった仕組みを理解した上で、Elasticsearch クラスタ管理を行うため、Dockerで小規模なElasticsearchクラスタを用意し、手順を追ってトレーニングし、理解を深めたいと考えました。
環境
Docker により、以下のコンテナような構成でコンテナを用意する。
- Elasticsearch node × 3
- Kibana node × 1 (こちらは必須ではありませんが、起動していれば curl の代わりに console 機能から各APIを実行することができます)
今回はこちらの記事の内容で構築しいたものを使いました。
https://qiita.com/blueskyarea/items/ebf219c413d0329ceb4f
$ curl -XGET -s "http://localhost:9200/_cluster/health" | python -m json.tool
{
"active_primary_shards": 7,
"active_shards": 14,
"active_shards_percent_as_number": 100.0,
"cluster_name": "es-docker-cluster",
"delayed_unassigned_shards": 0,
"initializing_shards": 0,
"number_of_data_nodes": 3,
"number_of_in_flight_fetch": 0,
"number_of_nodes": 3,
"number_of_pending_tasks": 0,
"relocating_shards": 0,
"status": "green",
"task_max_waiting_in_queue_millis": 0,
"timed_out": false,
"unassigned_shards": 0
}
実践
停止前
レプリカシャードのリバランシングを無効化する
前述したようにノードを停止すると、シャードのリバランシングが行われ、それに多くの時間を要してしまいます。
レプリカシャードのリバランシングを無効化することで、リバランシングによる不要なデータの移動を行わないようにします。
curl -XPUT "http://localhost:9200/_cluster/settings" -H 'Content-Type: application/json' -d'{ "persistent": { "cluster.routing.allocation.enable": "primaries" }}'
成功すれば、以下のようなレスポンスが返ってくるはずです。
{"acknowledged":true,"persistent":{"cluster":{"routing":{"allocation":{"enable":"primaries"}}}},"transient":{}}
synced flushを実行する
synced flushを予め実行しておくことで、ノード起動時に発生するプライマリシャードとレプリカシャードの内容が同じであることの確認を高速化することができる(ようです)。
curl -XPOST "http://localhost:9200/_flush/synced"
成功すれば、以下のようなレスポンスが返ってくるはずです。
各 index に対して、failed が 0 であることを確認します。
{"_shards":{"total":12,"successful":12,"failed":0},".apm-custom-link":{"total":2,"successful":2,"failed":0},".kibana_task_manager_1":{"total":2,"successful":2,"failed":0},"my_index":{"total":2,"successful":2,"failed":0},".apm-agent-configuration":{"total":2,"successful":2,"failed":0},".kibana-event-log-7.8.1-000001":{"total":2,"successful":2,"failed":0},".kibana_1":{"total":2,"successful":2,"failed":0}}
現 Master ノードを確認する
Masterノードを先に停止すると、不要なMasterノードの選定処理が行われます。
停止する目的にも依りますが、Masterノードは最後に停止するようにした方が良いと思いますので、現Masterノードはどれであるかを予め確認しておきます。
$ curl -XGET "http://localhost:9200/_cat/nodes?v"
ip heap.percent ram.percent cpu load_1m load_5m load_15m node.role master name
172.30.10.2 62 92 5 0.26 0.26 0.35 dilmrt * es02
172.30.10.3 20 90 5 0.26 0.26 0.35 dilmrt - es03
172.30.10.1 42 90 5 0.26 0.26 0.35 dilmrt - es01
停止
docker の コンテナを停止することになるので、実際にサーバのメンテナンスすることのシミュレートにはなりませんが、停止の流れをつかむために入れました。
ここでは例えば、es03 を停止することとします。
docker stop es03
もし実際のサーバを対象にする場合は、systemctl で停止する流れになります。
systemctl stop elasticsearch
es03 が停止されたことを確認できました。
$ curl -XGET "http://localhost:9200/_cat/nodes?v"
ip heap.percent ram.percent cpu load_1m load_5m load_15m node.role master name
172.30.10.1 18 82 5 0.27 0.68 0.95 dilmrt - es01
172.30.10.2 67 80 5 0.27 0.68 0.95 dilmrt * es02
必要に応じて、他のノードも順次停止していきます。
今回はクラスタの停止、起動の練習なので、メンテナンス的なことは何も行いませんが、実運用ではノードのメンテナンス(パッチの適用やハードウェアのメンテナンス)などを行います。
起動
ノードメンテナンスが完了したら、elasticsearch サービスを起動していきます。
起動する順序としては、Master(Master-eligible) ノードを先に起動して、クラスタの形成を優先して行うようにします。
そうすることで、データ専用ノード上で余分なエラーログの発生を抑制することができます。
ここでは、1ノードのみ(es03)停止していましたので、それをまず起動してきます。
docker start es03
もし実際のサーバを対象にする場合は、以下のようなコマンドでスタートすることになります。
systemctl start elasticsearch
以下のように、es03 がクラスタに再参加されたことを確認できました。
(数分かかる場合があります)
$ curl -XGET "http://localhost:9200/_cat/nodes?v"
ip heap.percent ram.percent cpu load_1m load_5m load_15m node.role master name
172.30.10.1 61 82 50 1.39 0.54 0.72 dilmrt - es01
172.30.10.3 57 79 50 1.39 0.54 0.72 dilmrt - es03
172.30.10.2 54 81 50 1.39 0.54 0.72 dilmrt * es02
起動後の確認
以下のコマンドで、クラスタの状態を確認していきます。
$ curl -XGET "http://localhost:9200/_cluster/health"
以下のようにクラスタの状態が表示されます。
すべてのプライマリシャードの配置が完了するまでは、ステータス(status)は red になります。
すべてのプライマリシャードの配置が完了すると、ステータス(status)は yellow になります。
{
"cluster_name" : "es-docker-cluster",
"status" : "yellow",
"timed_out" : false,
"number_of_nodes" : 3,
"number_of_data_nodes" : 3,
"active_primary_shards" : 7,
"active_shards" : 7,
"relocating_shards" : 0,
"initializing_shards" : 0,
"unassigned_shards" : 7,
"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" : 50.0
}
しかしながらこのままでは、ステータスは green に戻らないです。
レプリカシャードのバランシングを無効化しているためです。
レプリカシャードのリバランシングを有効化する
$ curl -XPUT "http://localhost:9200/_cluster/settings" -H 'Content-Type: application/json' -d'{ "persistent": { "cluster.routing.allocation.enable": null }}'
{"acknowledged":true,"persistent":{},"transient":{}}
ステータス(status)が green に戻ることが確認できました。
これで全てのレプリカシャードも余分なリバランスが行われることなく、正常に配置されていることになります。
$ curl -XGET "http://localhost:9200/_cluster/health"
{
"cluster_name" : "es-docker-cluster",
"status" : "green",
"timed_out" : false,
"number_of_nodes" : 3,
"number_of_data_nodes" : 3,
"active_primary_shards" : 7,
"active_shards" : 14,
"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
}
Elasticsearch クラスタの停止準備、停止、起動の操作を確認していきました。
「このタイミングでクラスタのステータスはどうなっているのだろう?」とか、実際に手順に沿って操作していると、気づくことが多いと思いますので、こういった簡易の形式でも実際に試してみると良いと思います。
練習用に実際にサーバを複数台用意するのはコストがかかりますが、コンテナを使う方法では1台のパソコンで十分に確認ができます。