はじめまして、Gunosyでサーバーサイドエンジニアをしているmanoと申します。 最近ハマっていることは、Huluで安室奈美恵さんの特番をみることです。引退するなんて・・・本当に惜しいですね。
私は現在ニュースパスというアプリのサーバーサイド開発を担当しています。
ニュースパスでは、記事検索機能等でElasticsearchを使っています。運用周りではcuratorを使っています。
最近そのあたりでハマってしまったことがあったので、今回はそれについて書こうと思います。
起こったこと
開発環境にて、Elasticsearchのノードインスタンスをシャットダウンしたときに、いくつかのシャードがunassignedになりステータスもred
となってしまうということがありました。
それでも検索機能は生きてはいたのですが、それによりレスポンスタイムが大幅に増加してしまっていました。
下の画像は当時のElasticsearch clientのELB Latencyです。平均値で20秒近くと、通常の200倍程度になっていました。
とりあえず応急処置を施すことにしました。
※ニュースパスでは、Elasticsearchからデータがロストしても後から復旧可能なため、こちらの応急処置は「unassignedになっているシャードは、いったんはデータ復旧しなくていい」というときの応急処置です。
現状確認
まずはクラスタのステータスを確認
$ curl -XGET host:9200/_cluster/health { "cluster_name": "クラスタ名", "status": "red", "timed_out": false, "number_of_nodes": 13, "number_of_data_nodes": 9, "active_primary_shards": 170, "active_shards": 340, "relocating_shards": 0, "initializing_shards": 0, "unassigned_shards": 112, "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": 75.22123893805309 }
うーん、"status": "red"
です。そしてunassigned_shards
はあるけどdelayed_unassigned_shards
はないから、この後自助作用で復旧することはなさそう。
次に、実際にunassignedとなっているシャードの情報を取得します。
$ curl -XGET host:9200/_cat/shards?h=index,shard,prirep,state,unassigned.reason index-1 2 p STARTED index-1 2 r STARTED index-1 3 r UNASSIGNED NODE_LEFT index-1 3 p UNASSIGNED NODE_LEFT index-1 1 r STARTED index-1 1 p STARTED index-1 5 p UNASSIGNED NODE_LEFT index-1 5 r UNASSIGNED NODE_LEFT index-1 4 p STARTED index-1 4 r STARTED
なるほど・・・index-1のシャード3・5が、primaryもreplicaもないと。
ここでバックアップデータからの復旧などができればそれをすればいいかと思いますが、今回はそういうのもなくて「とにかく犠牲を払ってでも復旧を!」というときの手段を書いていきます。(実行される方は自己責任でお願いします。。)
対処法
概要: 空のプライマリシャードをノードを指定してセットしていく
強引です(笑)
手順1 シャードを入れるノードのnode_idを取得
node_idがわかっているならスキップしても問題ありません。 サーバーIPアドレス等しかわからないとき、下記のように調べていきます。
$ curl -XGET host:9200/_nodes/(nodeサーバーのIPアドレスなど)
設定によっては1サーバー内に複数のノードがあるためです。
(後述のnode.max_local_storage_nodes
が2以上で設定されているとき)
手順2 空のプライマリシャードをセットしていく
こちらを参考に、rerouteコマンドにて空のプライマリシャードを突っ込んでいきます。
curl -XPOST 'http://localhost:9200/_cluster/reroute' -d '{ "commands": [{ "allocate_empty_primary": { "index": "index-1", "shard": 3, "node": "node_id", "accept_data_loss": true } }] }'
これで、指定したノードに、指定したindex・shardの空プライマリデータがassignされます。
環境にもよるかとは思いますが数秒でassignされます。
このように欠損してしまった全てのシャードの空データをセットしていけば、unassignedシャードがなくなった時点でstatus greenに復旧します。
そもそも
なおそもそも、このようなシャードの欠損を起こりにくくするには、下記のパラメータを適切に設定すると効果があるかと思います。
- node.max_local_storage_nodesを1(=デフォルト)にしておく
本番環境ではまずしないかと思いますが、こちらが2以上になっていると、同一のサーバーインスタンスに同一シャードのprimary・replicaが保存されてしまう可能性があり、その状態でそのインスタンスが落ちるとallocateが正常にできずstatus redになります。 - delayed_timeoutを設定する
ノードのネットワークが瞬断したときなどのnode_left発生時、即座にallocateが動いてしまうと過大な負荷がかかってしまうため、allocateが動くまでの時間を遅延させるパラメータです。 (デフォルト: 1分)
最後に
Gunosyではニュースパス等自社サービスのサーバーサイドエンジニアを募集中です!
https://hrmos.co/pages/1009778707507720193/jobs/0000003hrmos.co