はじめに
Elasticsearch を本番運用する上での究極のゴールの一つが、ディザスタリカバリー(以下 DR)対応 です。「ノードが 1 台落ちても大丈夫」なクラスタは作れても、「データセンターごと消えてもきちんと動く」クラスタを構築するには、もう一段深い理解と設計が必要です。
本稿では、オンプレミスで 2 つ以上のデータセンター(以下 DC)上に中規模以上の Elasticsearch クラスタを構築運用するケースを前提に、DC 全障害に対する可用性を実現するためのポイントを解説します。対象のバージョンは v8 以上になります。
個々のトピックは一般の Blog 等でも見られるものですが、今回は高可用性をテーマにまとめ直しています。本稿の内容をマスターすることで、Elasticsearch の優れた分散システムへの包括的な理解が深まり、DR 対策だけでなく、ダウンスケールした小規模クラスタの最適化、つまり「何を諦めるか、どのようなトレードオフを行っているか」を意識した設計ができるようになります。また、日常の運用、トラブルシューティングにも役立つ知識が身につきます。
TL; DR
まとめると、こんな感じです(クリックで拡大)。
Master ノードの理解
まずは Elasticsearch クラスタの可用性を語る上で最も重要な概念、Master ノード(master-eligible ノード)について理解しておく必要があります。
Master ノードとは
Elasticsearch クラスタには必ず 1 台の Master ノードが存在し、クラスタ全体の管理を担います。
Master ノードはデータの読み書きとは独立した、いわゆる 管理プレーン(Control Plane) としての役割を負います。この Master ノードを維持することが、Elasticsearch の可用性設計における第一目標になります。
具体的には以下のような役割を担います。
- インデックスの作成・削除
- クラスタへのノードの参加・離脱の管理
- シャードをどのノードに割り当てるかの決定
- Cluster State の更新と全ノードへの配布
Cluster State とは、インデックスのマッピング・設定、シャードの配置表、ノード一覧など、クラスタ全体の構成情報をまとめた内部データ構造です。
現在の Master ノードを確認する方法
現在どのノードが Master を担っているかは _cat/master API で確認できます。
GET _cat/master?v
id host ip node
xBa3qj8kTJ2sKs7hbI4Q 10.0.0.1 10.0.0.1 node-1
master-eligible ノードとは
Master ノードは固定ではなく、クラスタの起動時や現行の Master ノードがダウンした際に master-eligible ノード 間の選挙によって動的に選ばれます。master-eligible ノードは elasticsearch.yml で node.roles に master を含むノードです。
# elasticsearch.yml の例
node.roles: [ master ] # master-eligible 専用(dedicated master)
node.roles: [ master, data ] # master-eligible かつ Data ノードを兼ねる構成
現在の master-eligible ノードは _cat/nodes?v API で確認できます。node.role 列に m を持つノードが master-eligible ノードであることを示しており、master 列の * が現在の Master ノードを示します。
GET _cat/nodes?v
ip heap.percent ram.percent cpu load_1m node.role master name
10.0.0.1 45 72 3 0.12 m * node-1
10.0.0.2 38 68 2 0.10 m - node-2
10.0.0.3 41 70 2 0.11 m - node-3
10.0.0.4 62 80 5 0.30 d - node-4
Split-brain 問題
2 つの DC にまたがるクラスタを運用中に、DC 間のネットワークが突如断絶した場合、このクラスタはどうなるでしょうか?ネットワークが断絶しただけですので、各々の DC の内部ではノードが動いている状態です。それぞれの DC 内のグループが独立して Master を選出してしまうと、2 台の Master が別々の Cluster State を管理することになり、クラスタとしてのデータの一貫性が失われます。これがいわゆる Split-brain 問題です。
Elasticsearch では、この問題を次に説明する Raft と Quorum を用いて解決します。
Raft と Quorum による Master 選出と Split-brain の防止
v7.0 以降の Elasticsearch では、Master 選出と Cluster State 管理に Raft をベースにした独自のコンセンサスアルゴリズムを実装しています。これは、Master 候補が他のノードに投票を要求し、過半数の票を集めた候補だけが Master に選出されるという仕組みです。
この「過半数」を定式化したものを Quorum と呼びます。
Quorum = floor(N / 2) + 1
(N = master-eligible ノード数)
例:
N = 3 → Quorum = 2(3台中2台の賛成で Master 選出)
N = 5 → Quorum = 3(5台中3台の賛成で Master 選出)
Master 選出時には、master-eligible ノードが過半数の投票を要求することで、「どんな分断が起きても Quorum を満たすグループは同時に 2 つ存在できない」ことが数学的に保証されます。先ほどの例で言えば、分断されたどちらかのグループは必ず Quorum を下回るので Master を主張しなくなる結果、Split-brain を防止できる、という仕組みです。
もし master-eligible が偶数台だったら?
前述の Split-brain を避けるため、master-eligible は奇数台で構築するのが大前提です。
もし偶数の master-eligible ノードが存在する場合、Elasticsearch はそのうちの 1 台を Voting Configuration から自動的に除外し、master-eligible ノードを奇数に保つ機構が組み込まれています。このため、偶数の master-eligible で構成されたクラスタでも、Split-brain が発生することはありません。
ちなみに、Voting Configuration とは、新しい Master の選出や新しいクラスタ状態のコミットなどの決定を行う際に、応答がカウントされる master-eligible ノードのセットです。Voting Configuration 内のノードの半数以上が応答した後にのみ決定が下されます。
master-eligible ノードの設計ポイント
以上を踏まえた上で、実際に master-eligible ノードをどのように設計すれば良いか、DR 対策を前提とした設計のポイントを見ていきましょう。
master-eligible ノードのスペック
Master ノードは Data ノードのようなインデックスの読み書きの処理を行わないため、ハードウェアリソースの割り当ては控えめで十分なケースがほとんどです。
一般的には以下のスペックが適用されます。
- CPU: 4-8 vCPU
- メモリ: 8-16 GB
- ディスク: 100-200 GB
公式ドキュメントには 3,000 インデックスあたり Master ノードに 1GB のヒープメモリという基準が掲載されていますので、インデックス数が多い場合はノードメモリを多めにしておくことを検討します。
master-eligible ノードは 3 台
master-eligible ノードは 専用のハードウェア(VM)3 台で構成 がベストプラクティスです。
5 台構成の場合は 2 台同時障害まで耐えられますが、このシナリオが実際に発生する確率は非常に低く、採用する妥当性はほぼないと考えて良いです。
また、Data ノードと master-eligible ノードを兼ねる構成は、Master ノードの安定性を損ないクラスタ全体の遅延を招くリスクがあるため、(DR を意識するような)中規模〜大規模クラスタでは推奨しません。
完全な高可用性には 3 拠点が必要
2 つ DC を運用する環境では、片方の DC に master-eligible を 2 台、もう一方の DC に 1 台の master-eligible ノードを配置すれば、Split-brain は防止できます。
しかし、master-eligible が 2 ノード存在する DC が丸ごとダウンすると、残りの DC の 1台では Quorum(3 台構成の場合は 2)を満たせないため、Master を選出できず、クラスタが停止してしまいます。
このため、どちらの DC が落ちてもクラスタが継続稼働する「対称的な高可用性」を実現するには、3 拠点が必要になります。
Tiebreaker 専用の拠点を用意する
本格的なデータセンターを 3 つ維持するのはコストも運用負荷も大きいため、多くの組織では 2DC 構成が一般的です。
このようなケースでは、クラウドを利用して 小規模な「第 3 の DC」 を用意し、そこに master-eligible ノードを置くというアプローチがあります。この第 3 拠点の役割はあくまで Tiebreaker(調停役)、2つの DC の間で「どちらが生きているか」の投票に参加するためだけの存在です。
Tiebreaker アーキテクチャは分散システムにおける定石であり、MongoDB の Arbiter や Redis Sentinel など、Quorum ベースの合意形成を行う多くのシステムで同様のアプローチが採用されています。クラウド版 Elasticsearch(Elastic Cloud Hosted)でもこの構成が採用されています。
Voting-only master-eligible ノードの活用
通常の master-eligible ノードを第 3 拠点に置くと、そのノードが Master に選出されてしまう可能性があります。小規模・遠隔地の拠点で Master ノードが稼働してしまうと、Cluster State 管理の応答が遅延し、クラスタ全体の性能に影響します。調停役として置いたはずのノードに、本番の Master ノードの責務を担わせたくはありません。
ここで voting-only master-eligible ノードが登場します。voting-only master-eligible ノードは以下のような特徴を持っています。
- Master 選出の投票には参加するが、Master には選出されない
- データを持たない、送受信しない
- やることは「投票に参加する」だけ
voting-only master-eligible ノードは Master ノードに選出されないことが保証されるため、レイテンシーの高い遠隔拠点に安心して配置でき、最小スペックのクラウドインスタンス 1 台で十分に機能します。
Voting-only master-eligible ノードを作るには、elasticsearch.yml の node.roles に voting_only を同時に指定します。
node.roles: [ master, voting_only ]
Data ノードの設計ポイント
ここまでは管理プレーンの要である Master ノードの設計について見てきました。次はデータプレーン、つまり実際のデータを保持する Data ノードの設計ポイントについて見ていきましょう。
Shard Allocation Awareness を設定する
Elasticsearch はデフォルトで 1 つのインデックスの Primary シャードと Replica シャードを別ノードに置くことを保証していますが、これらを別々の DC に置くことは保証していません。Elasticsearch ノードは「自分がどの DC にいるか」を認識していないため、シャード割り当ての際に DC を考慮できないのです。
このままでは、Primary シャードと Replica シャードが同一 DC 内の別ノードに収容されてしまい、DC ごと断絶した際に、片寄せインデックスがリカバリー不能になるリスクがあります。
これを防ぐのが Shard Allocation Awareness です。複数の DC をまたぐクラスタでは、各ノードの elasticsearch.yml に zone 属性を付与し、Elasticsearch がシャードを配置する際にこの zone 属性を意識するように指示します。
# DC1 ノード
node.attr.zone: dc1
# DC2 ノード
node.attr.zone: dc2
# クラスタレベルで設定
PUT _cluster/settings
{
"persistent": {
"cluster.routing.allocation.awareness.attributes": "zone"
}
}
上記の設定を行ったクラスタで新しいインデックスを作成すると、Primary シャードと Replica シャードは dc1 と dc2 に分散して配置するようになります。
ちなみに、属性の名前は任意です。node.attr.availablity_zone や node.attr.data_center でも OK です。値も任意で、tokyo と osaka などの地名を利用するケースもよく見られます。
2N 構成でリソースを確保する
題名の通り、「片側 DC が完全に落ちても、もう片方だけで全てのワークロードを賄える」クラスタを構築するには、上述の設計・設定に加えて、片側のリソースだけのクラスタ全体のワークロードを支えるキャパシティを確保する、いわゆる 2N 構成 にするのが理想です。
ただし実際には各種コストの問題もあるため、「実際の危機が起こった際のクラスタ性能をどのレベルで確保するか」という性能とコストのトレードオフになります。
具体的には下記の点を考慮して、ノードの数やハードウェアスペックを決定します。
- ディスク容量:全シャード(Primary + Replica)を収容できるか、最悪 Replica は諦めても Primary だけは収容できるか
- ヒープ / メモリ:データキャッシュ・シャード管理のオーバーヘッド
- インジェスト性能:ピーク時の書き込みスループットを処理できるか
- 検索性能:クエリを片側のノード群だけで捌けるか
- Frozen ティア:片側にのみ存在していないか、オブジェクトストレージへのアクセス帯域は片側で十分か
- リカバリー処理余地:DC 障害発生時のリカバリー処理が、片側のリソースだけで通常ワークロードと並行して処理できるか
Data ノードのハードウェアスペックを均一にする
Shard Allocation Awareness を正しく設定し、トータルのキャパシティを確保しても、DC 間、あるいはティア内でノードのスペックや台数がバラバラな場合、Awareness が正しく機能せず、障害発生時のインデックスの可用性を損なうケースがあります。
CPU やメモリのスペックに差異があるケースはないと思いますが、DC 間でディスク容量に差異がある場合、Shard Allocation Awareness が正しく機能しない(障害発生時のインデックスの可用性を損なう)ケースがあります。
以下は極端な例ですが、DC1 と DC2 でノードのディスク容量が大きく異なる場合の挙動です。
DC1: node × 3(2TB each)
DC2: node × 3(500GB each)← 古いハードウェアなど
→ DC2 が先に low watermark にヒット
→ DC2 への新規割り当てが停止
→ 新しいシャードが DC1 に集中
→ Primary + Replica が DC1 に同居するケースが発生
low watermark を超えると割り当てが止まり、high watermark(デフォルト 90%)を超えると既存シャードの DC1 への移動(relocate)が始まり、偏りがさらに拡大します。
すべてのインデックスに Replica シャードを確保する
厳密には Data ノードというより各インデックスの設定になりますが、DC 障害時にデータを失わないためには、すべてのインデックスが 最低 1 つの Replica シャードを持っている必要があります。Replica シャードが存在しないインデックスは、そのインデックスの Primary シャードが存在する DC が落ちた時点でデータにアクセスできなくなります。
Replica シャード数の設定は、各インデックスの Settings 内で以下の値を設定します。デフォルトは 1 です。
PUT index-1/_settings
{
"index": {
"number_of_replicas": 1
}
}
インデックスの Primary シャード、Replica シャードの数は以下のコマンドで確認することができます。rep 欄が 0 のインデックスが存在しないか、定期的に確認することを推奨します。
# インデックスの Replica 数を確認
GET _cat/indices?v&h=index,pri,rep,health
なお、Cold または Frozen ティアで Searchable Snapshots によってロードされたインデックスはこのルールの例外です。Searchable Snapshots はオブジェクトストレージ上のスナップショットからデータを読み取るため、ローカルの Replica シャードを必要としません。
クラスタ全体の可用性施策
以上、Master ノードと Data ノードの機構と設計について見てきました。最後に、クラスタ全体での DR 設計のポイントをまとめます。
すべてのロールを二重化する
DR 構成では Master ノードと Data ノードに注目しがちですが、Ingest ノード、Coordinating-only ノード、ML ノードなど、クラスタ内で使用しているすべてのロールについて最低 2 台を確保し、DC をまたいで配置する必要があります。
特定のロールが 1 台しか存在せず、そのノードが障害 DC 側にあった場合、そのロールの機能がクラスタ全体で失われます。例えば Ingest ノードが 1 台だけで DC1 に配置されていた場合、DC1 の障害でインジェストパイプラインが停止し、データの取り込みが行えなくなります。
また、Kibana や Logstash についても同様です。Elastic Agent についてはネットワークデバイス等からデータを受け付ける先としてサーバー側で動作する場合、やはりサーバー側で二重化するのが安全です。
discovery.seed_hosts に master-eligible を列挙する
クラスタの Master ノードが変更になった際、新しい Master に追従できるよう、すべてのノードの elasticsearch.yml の discovery.seed_hosts にすべての master-eligible ノードを列挙します。
# すべてのノードの elasticsearch.yml に設定
discovery.seed_hosts:
- master-1.dc1.example.com
- master-2.dc2.example.com
- master-3.dc3.example.com
この設定により、各ノードはクラスタ起動時や Master 障害時に master-eligible ノードを発見し、Master 選出に参加できます。DC 障害で一部の master-eligible ノードに到達できなくなっても、生存側の master-eligible ノードへ接続できるため、クラスタへの再参加が可能です。
クライアントのルーティング先を分散する
Kibana・Logstash・Beats・Elastic Agent・カスタムアプリケーションなど、Elasticsearch に接続するすべてのクライアントが複数のElasticsearch ノードにトラフィックを分散するよう構成します。
クライアントが単一ノードや単一 DC のノードのみを参照している場合、そのノードや DC がダウンするとクライアント側から見てクラスタ全体が到達不能になります。Elasticsearch クラスタ自体が生存していても、クライアントがそれを認識できなければ意味がありません。
具体的には以下のいずれかの方法でルーティングを分散します。
- 複数ノードの直接指定:クライアントの接続先に両 DC の Data ノードや Coordinating-only ノードを列挙する
- ロードバランサーの利用:両 DC のノードをバックエンドに持つロードバランサーを経由する
# Kibana の例(kibana.yml)
elasticsearch.hosts:
- "http://data-1.dc1.example.com:9200"
- "http://data-2.dc2.example.com:9200"
運用上のポイント
ここまで解説した DR 対応のクラスタを安定して運用するためのポイントについて、いくつか見ていきましょう。
Cluster Health は常に green に
ここまで述べた設計と設定がすべて正しく機能していれば、Cluster Health は green になっているはずです。green はすべての Primary シャードと Replica シャードが正常に割り当てられている状態を意味します。平常時に Cluster Health が green であることは、DR 対策が機能するための前提条件です。
GET _cluster/health
{
"cluster_name": "my-cluster",
"status": "green",
...
}
Cluster Health が green から yellow に変化すると、Master ノードのログに以下のようなメッセージが出力されます。
[INFO ][o.e.c.r.a.AllocationService] [master-1] Cluster health status changed from [GREEN] to [YELLOW] (reason: [...]).
Cluster Health が yellow の場合、いずれかのインデックスで Replica シャードが未割り当てであることを意味します。この状態で DC 障害が発生すると、Replica が存在しないインデックスのデータが失われるリスクがあるため、早急に問題を解消し、Cluster Health を green に戻す必要があります。
障害発生時の挙動
DC に大規模な障害が発生したり、DC 間のネットワークが断絶すると、Elasticsearch クラスタは以下のような対応を行います。
- Master ノードの選出: Quorum を満たす DC 側で Master ノードが選出され、クラスタは継続稼働します。
- Primary シャードの昇格: 断絶された DC にあった Primary シャードは利用できなくなります。Elasticsearch は生存側の DC 内で Replica シャードを Primary シャードに昇格させ、当該インデックスへの書き込みを復旧します。
- リカバリーの実行: Replica シャードが失われたインデックスに対して、Primary シャードから Replica を再作成するリカバリー処理が自動的に開始します。
この際、Master ノードのログには、ノードが離脱したことを示す以下のようなメッセージが出力されます。
[INFO ][o.e.c.c.NodeLeftExecutor] [master-1] node-left: [{data-1}{...}] with reason [disconnected]
また、この障害により Master ノードが変更された場合は、以下のようなメッセージが出力されます。
[INFO ][o.e.c.s.ClusterApplierService] [data-1] master node changed {previous [...], current [...]}, ...
復旧時の挙動
反対に、断絶していた DC が復旧してノードがクラスタに再参加すると、以下のイベントが発生します。
- Master ノードの再選出: クラスタは Quorum を再評価し、必要に応じて Master ノードを再選出します。
- シャードの再配置: 復旧した DC にシャードが再配置されます。Shard Allocation Awareness の設定に従い、Primary と Replica が同一 DC に同居しないように割り当てられます。
- リカバリーの再実行: 復旧した DC のノードに対して、必要に応じてシャードのリカバリーが再度実行されます。
- リバランスの実行: 復旧したクラスタ全体でシャードの配置が最適でないと判断される場合、Elasticsearch はリバランス処理を開始します。
復旧時には、ノードがクラスタに再参加したことを示す以下のようなログが出力されます。
[INFO ][o.e.c.c.NodeJoinExecutor] [master-1] node-join: [{data-1}{...}] with reason [joining after restart]
モニタリング専用クラスタを利用した監視と通知
Elasticsearch には Stack Monitoring という、クラスタのメトリックやログを収集・監視するための機構が用意されています。最小の環境ではクラスタが自分自身にこれら監視データを送信し、自分自身をモニタリングすることができますが、これは本番ではおすすめできません。本番運用ではモニタリング専用クラスタを(本稿に記載した要領で)構築し、メインクラスタを単独で監視するように構築するのがベスト・プラクティスです。
この Stack Monitoring を設定し、組み込みのクラスタ監視ルール を利用することで、上述したようなクラスタの状態変化が発生した際、運用担当者に対して素早く通知が行くように構成することができます。
リカバリー/リバランス処理の状況を把握する
クラスタノードの離脱や再参加などで発生するリカバリー/リバランス処理の状況は、いずれも _cat/recovery API で確認することができます。
GET _cat/recovery?v&active_only=true
index shard time type stage source_node target_node bytes_percent
myindex 0 1.2m peer translog node-1 node-4 85.3%
myindex 1 0.8m peer index node-2 node-5 62.1%
active_only=true を指定することで進行中の処理のみを表示します。戻りが空になったら、リカバリー/リバランスが完了した、と考えて OK です。
Stack monitoring を利用している場合は、Cluster overview ダッシュボードの Recovery status からも同じ情報が確認できます。これと各 Data ノードの CPU やメモリの利用状況、GC 発生状況を併せて監視することで、Data ノードに過剰な負荷がかかっていないかを確認することができます。
リカバリー/リバランス処理の負荷を調整する
リカバリーとリバランスはいずれもノードの I/O・CPU・ネットワーク帯域を消費し、通常のワークロードと競合するため、実際の発生時、運用担当者はクラスタの状況を注意深く監視する必要があります。
Elasticsearch には、このリカバリーとリバランスの同時実行数と帯域を制御する設定があります。リカバリー/リバランス処理が通常のワークロードに悪影響を与える場合は、これらの設定を調整することで影響を緩和します。反対に、リカバリー/リバランスを迅速に完了させたい場合は、同時実行数や帯域を増やすことも可能です。
例:
PUT _cluster/settings
{
"persistent": {
"cluster.routing.allocation.node_concurrent_recoveries": 4,
"cluster.routing.allocation.cluster_concurrent_rebalance": 4,
"indices.recovery.max_bytes_per_sec": "100mb"
}
}
設定可能な値は以下の通りです。
| 設定 | 対象 | 意味 | デフォルト |
|---|---|---|---|
node_concurrent_recoveries |
リカバリー | 1ノードあたりの同時実行数(incoming/outgoing 共通) | — |
node_concurrent_incoming_recoveries |
リカバリー | 1ノードあたりの受信同時実行数 | 2 |
node_concurrent_outgoing_recoveries |
リカバリー | 1ノードあたりの送信同時実行数 | 2 |
cluster_concurrent_rebalance |
リバランス | クラスタ全体の同時実行数 | 2 |
indices.recovery.max_bytes_per_sec |
共通 | 1ノードあたりの帯域上限 | 40MB |
リカバリーの同時実行数はノード単位、リバランスの同時実行数はクラスタ全体で制御する点に注意してください。indices.recovery.max_bytes_per_sec は名前に反してリバランスにも適用されます。Elasticsearch 内部ではリバランス(シャード再配置)もリカバリーと同じコードで実装されているためです。
これらはいずれも動的に変更可能(クラスタ再起動不要)なため、平常時はデフォルトで運用し、障害発生時・復旧時に状況を見ながら調整する運用も可能です。
まとめ
本稿では、データセンター障害に耐える Elasticsearch クラスタを構築するための設計ポイントを解説しました。要点を振り返ります。
- Master ノード: 専用ハードウェア 3 台、3 拠点に分散配置。第 3 拠点には voting-only ノードを活用
- Split-brain 防止: Raft ベースの Quorum(過半数合意)により、分断時も Master は最大 1 台に制限される
- Data ノード: Shard Allocation Awareness で Primary と Replica を別 DC に配置。ハードウェアスペックは DC 間で均一に
- 2N 構成: 片側 DC だけで全ワークロードを処理できる 2N 構成が理想
- 全ロールの二重化: Ingest・Coordinating-only・ML・Kibana・Logstash 等もすべて DC をまたいで冗長化
- クライアント: 接続先を複数 DC に分散し、単一障害点を排除
- 平常時の監視: Cluster Health が green であることが DR の前提条件
- 独立したモニタリングクラスタ: モニタリング専用クラスタでメインクラスタの状態変化を監視・通知
- 障害・復旧時: リカバリー・リバランスの同時実行数と帯域を状況に応じて動的に調整
いかがでしたでしょうか?DR 対策は、Elasticsearch の分散システムとしての理解を深める絶好のテーマであり、設計・運用の両面で多くの学びがあります。また、DR 対策は「設定して終わり」ではなく、平常時からの継続的な監視と、障害発生時・復旧時の適切なオペレーションが組み合わさって初めて機能します。本稿が、皆さんの Elasticsearch クラスタをより堅牢にする一助になれば幸いです。
参考資料
- Availability and resilience — 可用性設計の全体像
- Resilience in small clusters — 小規模クラスタにおけるレジリエンス設計
- Discovery and cluster formation — Master ノードの選出の仕組み
- Voting configurations — Voting Configuration の詳細
- Cluster state — Cluster State の概要
- Shard allocation awareness — Shard Allocation Awareness の設定
