こんにちは。MAMADAYSバックエンドチームのsa9sha9です。最近Diablo3にハマりました。
MAMADAYSでは検索基盤としてElasticsearch(以下ES)を利用していますが、時たま再起動を実施したいケースがあります。
本記事では、ゼロダウンタイムでのESの再起動を実現するための注意点を実際のフローに沿ってまとめたいと思います。
MAMADAYSのアーキテクチャについては以前のTechBlogをご参照ください。
おことわり
本記事でご紹介する手順については必ずしもご自身の環境とマッチするか保証しかねます。 バージョンごとの差異については、しっかりと公式ドキュメントにてご確認ください。
安直に再起動ができない理由
ESを利用する場合には複数台のクラスタ構成にするのが常かと思いますが、ESクラスタを安直に再起動してしまうとダウンタイムが発生してしまいます。
検索機能が主機能なサービスの場合には致命的な障害となってしまうでしょう。
MAMADAYSでは3台のノードでクラスタを構成していますが、それぞれのノードを1台ずつ再起動することでゼロダウンタイムでの再起動を目指します。
再起動の準備体操
1. ヘルスチェック
必ずはじめにヘルスチェックを行いましょう。
ここでステータスが yellow
/ red
だった場合は必ず settings や shards の状態を確認し、 green
ステータスにしてから再起動に臨みましょう。
GET _cat/health
// 結果
epoch timestamp cluster status node.total node.data shards pri relo init unassign pending_tasks max_task_wait_time active_shards_percent
1645172581 08:23:01 mamadays-es-cluster green 3 3 xxx xxx 0 0 0 0 - 100.0%
2. ノード一覧の確認
現時点でどのノードが master node になっているかを確認しましょう。
そして再起動する際には、 master node は最後に再起動しましょう。
というのも master node が停止した場合、別のノードが master node に成り代わるわけですが、最初に master node を停止すると master node の移動が最低でも2回行われてしまいます。
master node の再起動を最後に行うことで master node の移動は必ず1回になるので、余計な移動を避けられます。
GET _cat/nodes?v
// 結果
ip heap.percent ram.percent cpu load_1m load_5m load_15m node.role master name
192.168.1.95 37 88 1 0.11 0.07 0.02 dilm - ip-192-168-1-95
192.168.2.238 27 89 1 0.00 0.00 0.00 dilm - ip-192-168-2-238
192.168.3.72 24 89 1 0.04 0.01 0.00 dilm * ip-192-168-3-72
3. インデックスの状態を確認
再起動後にデータの欠落がないか確認するため、 docs.count
を控えておきましょう。
GET _cat/indices/index_01?v
// 結果
health status index uuid pri rep docs.count docs.deleted store.size pri.store.size
green open index_01 xxxxxxxxxxxxxxxxxxxxxx 3 1 x 0 x.xmb xxx.xkb
4. 自動アロケーション機能を無効化
ESは replica shards の存在が確認できないと、別ノードに新たな replica shards が作成されます。ノードの再起動をかけた際に一時的に replica shards が確認できなくなるためこの処理が実行されます。
ただし、すぐに複製を開始するわけではなく、デフォルトでは1分間待機してから複製を開始します。
再起動だけなのでほぼ1分以内にノードは復旧するはずですが、何らかの理由で1分を超えてしまうと不要な複製処理が行われ膨大なI/Oが発生してしまうため、作業中は自動複製を停止しておきましょう。
ただし、primaries
を指定して primary shards を他のノードへ再配置することは許可しておきましょう。
PUT _cluster/settings
{
"persistent": {
"cluster.routing.allocation.enable": "primaries"
}
}
// 結果
{
"acknowledged" : true,
"persistent" : {
"cluster" : {
"routing" : {
"allocation" : {
"enable" : "primaries"
}
}
}
},
"transient" : { }
}
5. 機械学習機能が有効になっている場合は停止
もし機械学習機能を使っているなら、一時的に停止しましょう。
MAMADAYSでは使っていないのでこの手順はスキップします。
これで再起動準備は整いました!
いざ、再起動
1. 各ノードに入ってプロセスを再起動
sudo systemctl restart elasticsearch.service
必須ではありませんが、この時に他の生きているESノードに1sごとに _cat/shards
APIでシャード状態を確認すると、 primary shard の再配置の動きが肌で感じられてとても良いです。
2. (1つ目のノードの再起動を行った後に) 試しにヘルスチェック
1つ目のノードを再起動したタイミングでヘルスチェックを行うと、ステータスが yellow
になっているかと思います。
これは replica shards が一時的に切り離されたことによるもので、検索機能に影響はありません。
GET _cat/health
// 結果
epoch timestamp cluster status node.total node.data shards pri relo init unassign pending_tasks max_task_wait_time active_shards_percent
1645170501 07:48:21 mamadays-es-cluster yellow 3 3 xxx xxx 0 0 xxx 0 - 66.7%
3. (全ノードの再起動を行った後に) ノードとインデックスの確認
master nodeの位置が変わっているはずです。
GET _cat/nodes?v
// 結果
ip heap.percent ram.percent cpu load_1m load_5m load_15m node.role master name
192.168.1.95 37 88 1 0.11 0.07 0.02 dilm * ip-192-168-1-95
192.168.2.238 27 89 1 0.00 0.00 0.00 dilm - ip-192-168-2-238
192.168.3.72 24 89 1 0.04 0.01 0.00 dilm - ip-192-168-3-72
GET _cat/indices/index_01?v
// 結果
health status index uuid pri rep docs.count docs.deleted store.size pri.store.size
green open index_01 xxxxxxxxxxxxxxxxxxxxxx 3 1 x 0 x.xmb xxx.xkb
4. 後処理
自動アロケーション機能を有効化
PUT _cluster/settings
{
"persistent": {
"cluster.routing.allocation.enable": null
}
}
// 結果
{
"acknowledged" : true,
"persistent" : { },
"transient" : { }
}
5. (必要なら) 機械学習機能を有効化
MAMADAYSでは使っていないのでスキップ。
6. 各方面のチェック
WebやAppから検索機能が使えるかどうかなどを確認しましょう。
これにて、ESクラスタの再起動は完了です。
困った点
ロードバランサーが再起動中のESノードにも疎通させてしまい一定の確率で接続できなくなる
MAMADAYSではESの前面にロードバランサーを置いているのですが、ロードバランサーはESノードの死活状態を即時に検知しないため、ESノードの再起動の如何にかかわらず一定の確率で疎通させてしまいます。
ESノードの再起動中はもちろん応答ができないためエラーを返してしまい、結果としてダウンタイムが発生することになります。
そのため、ロードバランサーのターゲットグループから再起動させるESノードを予め除外し、再起動中は疎通させないようにしておく必要があります。
kibanaのアクセス先のESノードが落ちると、その間だけ状態確認ができなくなる
再起動中にも _nodes
APIなどで状態を確認したい場合は、curl で他のESノードのAPIを呼びましょう。
理想はkibanaが自動で障害検知して他のESノードへ接続してくれると良いんですが、どうにもそれができなかったので今回はやむなく上記の方法で対処しました。
Sniffingがそういった機能を有しているらしいのですが、うまく動作せず今回は見送りました。詳しい方がいればぜひ入社して欲しいです。
切り戻しについて
万が一何らかの障害が発生して、インデックスデータなどを失ってしまった場合に備えてsnapshotを取っておきましょう。
本記事では詳しい説明は省略しますが、バージョン違いによる互換性などは必ず確認することをお勧めします。
Snapshot and restore | Elasticsearch Guide [8.0] | Elastic
最後に
本来はこのようなトイルは自動化すべきなのですが、本件が緊急対応ということもあって手動で行うことになりました。
今後は、誰でも簡単かつ迅速かつ安全に実施できるようにAnsible化を行おうと考えています。