エンジニアリング

新世代Elasticsearchクラスターコーディネーション

Elasticsearchが広く普及した理由の1つは、数ノードの小規模なクラスターから数百ノードの大規模なクラスターへの拡張性が優れていることです。その中心にあるのが、クラスターコーディネーションサブシステムです。Elasticsearchバージョン7は、新たなクラスターコーディネーションサブシステムを備えており、これまでのバージョンと比べて多くの利点があります。この記事では、バージョン7においてこの新しいサブシステムに加えられた改善点について紹介し、その使い方、今回の変更がバージョン6からのアップグレードに与える影響、誤ってデータをリスクにさらしてしまうことを防ぐ新たな機能について説明します。そして最後に、新しいサブシステムの仕組みを説明する理論の概要を提示します。

クラスターコーディネーションとは

Elasticsearchクラスターを使用すると、多数のノードの連携を必要とするさまざまなタスクを実行できます。たとえば、検索で正確な結果を得るために、各検索はすべての適切なシャードにルーティングする必要があります。一部のドキュメントをインデックスまたは削除したときは、すべてのレプリカが更新される必要があります。すべてのクライアントリクエストは、それを受信するノードから、それを処理できるノードへと転送される必要があります。各ノードは、検索、インデックス、その他のコーディネーションアクティビティを実行するための独自のクラスター概要を備えています。この概要をクラスターステータスと呼びます。クラスターステータスにより、各インデックスのマッピングや設定、各ノードに割り当てられているシャード、 同期されているシャードコピーなどが分かります。きわめて重要なのは、クラスター間でこの情報の一貫性が維持されていることです。シーケンス番号ベースの複製クラスター横断レプリケーションなどの最近の多くの機能は、クラスターステータスが一貫していないと適切に機能しません。

コーディネーションサブシステムは、特定のノードをクラスターのマスターとして選出することで機能します。選出されたマスターノードにより、クラスター内のすべてのノードが確実に、クラスターステータスの更新を受信できるようになります。これは簡単なように思えるかもしれませんが、想像しているより難しいことです。Elasticsearchのような分散システムでは、多くの変則的な状況に対処できるように備えておかなければならないからです。ノードは動きが遅くなったり、ガーベージコレクションのために一時停止したり、突然停電することもあります。 ネットワークはパーティションやパケット損失、高レイテンシとなる時間帯などの影響を受けます。また、送信したときの順番とは異なる順番でメッセージが配信される可能性もあります。また、同時に複数の問題が発生する場合もあり、断続的に発生する場合もあります。そのようなことが発生したとしても、クラスターコーディネーションサブシステムは、各ノードが一貫したクラスターステータスビューを持つように保証できる必要があります。

重要なのは、Elasteicsearchは個々のノードの障害に対する回復力がなければならないことです。Elasticsearchでは、ノードのうちの一定数(クォーラム)がクラスターステータスの更新を受け入れたときにその更新が成功したと見なすことで、回復力を実現しています。このクォーラムは、慎重に選択された、クラスター内のマスター適格ノードのサブセットです。ノードのサブセットのみから反応を要求するというこの方法の利点は、一部のノードに障害が発生してもクラスターの可用性に影響しないことです。このクォーラムは、クラスターが2つの個別のマスターを選出しないようにするために慎重に選択する必要があります。マスターが2つ選出されると、一貫した決定を行えず、最終的にはデータ損失につながります。

通常は、クラスター内に3つのマスター適格ノードを含めることが推奨されます。ノードの1つに障害が発生しても、その他の2つで安全にクォーラムを形成し、続行できるからです。クラスター内のマスター適格ノードが2つ以下の場合は、そのいずれの障害にも耐えられません。それとは逆に、クラスター内にマスター適格ノードが4つ以上ある場合は、マスターの選出およびクラスターステータスの更新に時間がかかる可能性があります。

進化か革新か?

Elasticsearchバージョン6.x以前では、Zen Discoveryと呼ばれるクラスターコーディネーションサブシステムを使用しています。このサブシステムは数年の間に進化および成熟し、大規模および小規模なクラスターで活用されています。しかし、いくつかの改良点は、実装のためにサブシステムの動作に関する根本的な変更が必要でした。

Zen Discoveryでは、discovery.zen.minimum_master_nodes設定を使用することで、クォーラムを形成するマスター適格ノード数をユーザーが選択できます。この設定を各ノードで適切に設定し、クラスターの動的な拡張に合わせて適切に更新することが非常に重要です。しかし、システムがユーザーによる誤設定を検知することはできず、また実際の運用においてはノードの追加または削除後の調整作業を忘れてしまいがちです。Zen Discoveryは、マスター選出時に数秒待機し、それをこのような誤設定に対する保護対策としています。他のタイムアウトについても同様に慎重な設定となっています。これは、選出されたマスターノードに障害が発生した場合、それに代わるノードが選出されるまで、クラスターが利用不可になる決定的に重大な時間が少なくとも数秒間発生するということです。クラスターでマスターが選択できない場合、その理由を理解するのは非常に難しい場合があります。

Elasticsearch 7.0では、クラスターコーディネーションサブシステムについて、次のように再考および再構築を実施しました。

  • minimum_master_nodes設定は削除し、どのノードでクォーラムを形成するかをElasticsearch自身が選べるようにしました。 
  • 通常のマスター選出は、1秒未満で完了するようになりました。 
  • クラスターの拡張または縮小がより安全で簡単になり、データ損失のリスクを伴う方法でシステムが構成されるおそれが大きく低下しました。 
  • ノードのステータスが今までよりも明確にログされるようになりました。これは、クラスターの結合ができない理由やマスターが選出されない理由を診断するのに役立ちます。

ノードが追加または削除されると、Elasticsearchがクラスターの 投票設定を更新することで、最適なフォールトトレランスレベルを自動的に維持します。投票設定はマスター適格ノードのセットです。これらのノードによる投票が、決定の際にカウントされます。通常、投票設定にはクラスター内のすべてのマスター適格ノードが含まれています。クォーラムは、投票設定の過半数です。つまり、クラスターステータスのすべての更新には、投票設定内のノードの過半数からの同意が必要です。システムが投票設定を管理(つまりクォーラムを管理)することで、ノードが追加または削除された場合でも、データ損失につながるような誤設定の可能性を回避できます。

ノードがマスターノードを見つけられず、そのノード自体が選出されることができない場合、Elasticsearch 7.0以降では、そのノードの現在のステータスを十分な情報量で説明する警告メッセージが定期的にログされます。このログが多くの一般的な問題の診断に役立ちます。

さらに、Zen Discoveryではまれに、「Repeated network partitions can cause cluster state updates to be lost(ネットワークパーティションの繰り返しによりクラスターステータスの更新が失われる場合があります)」(Elasticsearch Resiliency Status ページに記載)という障害が発生しますが、これは今後発生しなくなります。この問題は解決済みとされました。

使用方法

新規にインストールしたElasticsearchノードをすべてデフォルト設定のまま使用し始めた場合、そのノードは同じホスト上で実行されている他のノードを自動的に探し、数秒後にクラスターを形成します。同じホスト上でさらに追加のノードを使用し始めると、それらの追加ノードもデフォルトでそのクラスターを見つけて参加します。これにより、これまでのバージョンと同様、Elasticsearchバージョン7.0でも複数ノードの開発クラスターを簡単に開始できます。

この完全自動クラスター形成メカニズムは、単一のホスト上で機能しますが、実稼働またはその他の分散環境で使用できるほど堅牢ではありません。ノード同士が特定の時間内にお互いを見つけることができないというリスクがあり、そのために2つ以上の個別のクラスターが形成される可能性があります。バージョン7.0以降では、複数のホスト上にノードがある新しいクラスターを開始する場合、クラスターが最初の選出で使用する投票設定として、マスター適格ノードの初期セットを指定する必要があります。これはクラスターブートストラップと呼ばれ、クラスターの最初の形成時のみに必要です。すでにクラスターに参加しているノードは、データフォルダ内に投票設定を格納し、再起動後にそれを再利用します。既存のクラスターに参加しようとしている新規に開始されたノードは、クラスターで選出されたマスターからその情報を受け取ることができます。

cluster.initial_master_nodes設定で、マスター適格ノードの初期セットの名前またはIPアドレスを設定することで、クラスターをブートストラップします。この設定はコマンドラインで、または1つあるいは複数のマスター適格ノードのelasticsearch.ymlファイルで提示できます。また、ノードがお互いを見つけられるようにディスカバリサブシステムを設定する必要もあります。

initial_master_nodesが設定されていない場合、新規ノードは、既存のクラスターを見つけることができるという前提で起動します。参加するクラスターを見つけられない場合、そのノードは次の内容の警告メッセージを定期的にログします。

master not discovered yet, this node has not previously joined a bootstrapped (v7+) cluster,
and [cluster.initial_master_nodes] is empty on this node

クラスターに新たにマスター適格ノードを追加する際に特別な手順を実行する必要はなくなりました。新しいノードを構成するだけで、そのノードは既存のクラスターをディスカバーし、起動します。そして、クラスターは新しいノードが追加されると、その投票設定を安全かつ自動的に適応させます。また、マスター適格ノードの過半数を同時に停止させない限り、ノードは停止させることで安全に削除できます。マスター適格ノードの過半数を停止させる必要がある場合、またはより複雑なスケーリングおよびオーケストレーションの必要性がある場合のために、ターゲットを絞ったスケーリング手順があります。この手順では、APIを使用して投票設定を直接調整します。

アップグレード方法

Elasticsearchクラスターは、ローリングアップグレードまたはクラスターの完全な再起動によって、バージョン6からバージョン7にアップグレードできます。推奨されるのはローリングアップグレードです。クラスターを使用できる状態に維持しながら、ノードごとにアップグレードを実行できます。バージョン6クラスターからバージョン6.7クラスターにアップグレードしてから、バージョン7へのローリングアップグレードを実行する必要があります。クラスターの完全な再起動の場合は、任意の6.xバージョンからバージョン7へのアップグレードが可能ですが、クラスター全体のシャットダウンと、その後の再起動が必要です。どちらの場合でも、バージョン6からバージョン7にアップグレードすると、ここで説明したクラスターコーディネーションの改善以外にも数多くの変更がElasticsearchに加えられています。スムーズにアップグレードするために、必ず詳細なアップグレードインストラクションに従ってください。

ローリングアップグレードを実行する場合は、クラスター内のノード数と既存のminimum_master_nodes設定に基づいて、クラスターブートストラップが自動的に実行されます。そのため、アップグレードを開始する前にその設定が正しいことを確認することが重要です。ローリングアップグレードではクラスターブートストラップが自動的に実行されるため、initial_master_nodesを設定する必要はありません。マスターの選出時に、バージョン7のマスター適格ノードはバージョン6.7のノードに優先的に投票します。そのため、マスター適格ノードのすべてをアップグレードするまでは、通常、バージョン6.7のノードがマスターとして選出されることが想定されます。

クラスターの完全な再起動を実行する場合は、上記で説明したように、アップグレードしたクラスターをブートストラップする必要があります。つまり、新たにアップグレードしたクラスターを開始する前に、まずinitial_master_nodesでマスター適格ノードの名前またはIPアドレスを指定する必要があります。

バージョン6以前では、discovery.zen.*名前空間でZen Discoveryの挙動を設定できるその他の機能がいくつかあります。これらの設定の一部はバージョン7では効果がないため削除されており、それ以外については名前が変更されています。バージョン7で設定の名前が変更されている場合、古い名前は廃止されているため、新しい名前を使用するように設定を調整する必要があります。

| 古い名前 | 新しい名前 | | --- | --- | | discovery.zen.ping.unicast.hosts | discovery.seed_hosts | | discovery.zen.hosts_provider | discovery.seed_providers | | discovery.zen.no_master_block | cluster.no_master_block |

新しいクラスターコーディネーションサブシステムには、新たな障害検出メカニズムが装備されています。つまり、discovery.zen.fd.*名前空間のZen Discoveryの障害検出設定は効果がなくなっています。バージョン7以降、ほとんどのユーザーにはデフォルトの障害検出設定の使用が推奨されます。ただし、変更が必要な場合はcluster.fault_detection*設定を使用して変更できます。

安全第一

Elasticsearchの7.0より前のバージョンでは、クラスターの一貫性にリスクがもたらされる安全ではない一連の手順を不注意によって実行してしまう可能性がありました。しかしバージョン7.0以降では、安全ではない手順を実行している可能性を明確に認識できるように通知され、続行するかどうかについての確認が要求されます。

たとえば、Elasticsearch 7.0クラスターでは、マスター適格ノードの過半数が永久に失われても、自動的に復元されません。クラスター内には3つのマスター適格ノードを持つことが一般的です。これにより、そのうちの1つが失われても、Elasticsearchはダウンタイムなしで継続して機能できます。そのうちの2つが永久に失われた場合は、その後、残りのノードが安全に機能し続けることはできません。

バージョン7.0より前のElasticsearchでは、そのような状況からクラスターを復元することができます。ユーザーは、失ったノード数と同数の空の新しいマスター適格ノードを起動し、置き換えることで、クラスターをオンラインに戻すことが可能です。マスター適格ノードの過半数の永久損失から自動的に復元することは危険です。残りのノードで、最新のクラスターステータスのコピーを持っていることが確実なノードはないからです。これはデータの損失につながります。たとえば、同期セットからシャードコピーが削除されていた場合です。そのことを残りのノードのすべてが認識していない場合、その古いシャードコピーがプライマリとして割り当てられる可能性があります。これに関する最大の危険は、この一連の手順によってクラスターにリスクがもたらされていることをユーザーがまったく認識していないことです。ユーザーが不一致に気づくのは、数週間後または数か月後になる可能性があります。

Elasticsearch 7.0以降では、このような安全ではないアクティビティは大幅に制限されます。クラスターは、このようなリスクを冒すよりも、利用不可のままでいることを優先します。バックアップがないというまれなケースでは、どうしても必要な場合に、このような安全ではないオペレーションを実行することは可能です。リスクについて認識していることを確認し、誤って危険なオペレーションを実行する機会を回避するために、いくつかの追加ステップが発生するだけです。

マスター適格ノードの過半数を失った場合、最初に試すべきなのは失ったマスター適格ノードをオンラインに戻すことです。ノードのデータディレクトリが失われていない場合は、それらのデータディレクトリを使用して新しいノードを開始することが最良の方法です。それが可能なら、最新のクラスターステータスを使用して安全に再度、クラスターを形成できます。

次に試すべき手順は、最近のスナップショットからクラスターを復元することです。これによってクラスターを既知の良好な状態に戻せますが、スナップショットを取った後に書き込んだデータは失われます。しかし、欠落している期間が分かっているため、その欠落しているデータを再度インデックスすることができます。スナップショットは増分バックアップのため、かなり頻繁に実行することが可能です。復元時に損失しているデータ量を少なくするために、30分ごとにスナップショットを取ることは珍しいことではありません。

どちらの復元操作も実行できない場合の最終手段は、安全ではないelasticsearch-node復元ツールを使用することです。これはシステム管理者が、古いマスターを少数派から選出するなどの安全ではない操作を実行するために使用できるコマンドラインツールです。Elasticsearch 7.0では、一貫性を壊す可能性のある手順を明確に示すことで、安全ではない一連の操作によって意図せずデータ損失を招くリスクが排除されています。

その仕組み

分散システムの理論について精通している方は、分散合意を使用して解決できる問題の例として、クラスターコーディネーションを認識しているかもしれません。 Elasticsearchの開発が開始されたとき、分散合意はそれほど広く理解されてはいませんでしたが、近年、最先端の技術が著しく進歩しました。

Zen Discoveryは分散合意アルゴリズムから多くのアイデアを採用しましたが、その理論が規定しているモデルに厳密に従うのではなく、有機的に採用しました。Zen Discoveryでもタイムアウトは慎重な設定となっているため、障害発生後の復元は非常に遅い場合があります。7.0での新しいクラスターコーディネーションサブシステムの導入では、その理論モデルにさらに厳密に従うことになりました。

分散コーディネーションは、適切に解決することが難しい問題として知られています。私たちは事前に設計を検証するために、正確性と安全性を確実に提供する自動化されたツールとともに、形式手法を大いに活用しました。Elasticsearchの新しいクラスターコーディネーションアルゴリズムの公式仕様については、公開されているElasticsearch公式モデルリポジトリをご覧ください。アルゴリズムの中核となる安全モジュールはシンプルかつ簡潔であり、Elasticsearchリポジトリの公式モデルとプロダクションコードの間は1対1で直接対応しています。

Paxos、Raft、Zab、Viewstamped Replication(VR)などの分散合意アルゴリズムのファミリーに精通していれば、中核となる安全モジュールについてもよく分かります。これは単一の書き換え可能なレジスタをモデル化し、Paxosの投票、Raftのターム、VRのビューに類似したマスター用語の概念を使用します。また、中核となる安全モジュールとその公式モデルは、クラスターブートストラップ、ノードの再起動における永続性、動的な再構成にも対応します。これらすべての機能は、システムがどのような状況でも適切に動作するために重要です。

論理的に強力なこのコアを中心に、liveness(活性) レイヤを構築しました。これにより、クラスターにどのような障害が発生した場合でも、その後ネットワークが復旧して十分なノード数がオンラインになれば、マスターが選出されてクラスターステータスを発行することができるようになります。この活性レイヤでは、いくつかの最新のテクニックを使用して多くの一般的な問題を回避します。選出スケジューラは適応型であり、ネットワーク状況によってふるまいを変え、過剰な選出不一致を回避します。Raftスタイルの事前投票ラウンドにより、選出不能となる事態を抑制し、不正ノードによる妨害を回避します。ラグ検知によって、マスターからの遅延が大きすぎるためにノードがクラスターを妨害することがないよう防止します。アクティブな双方向の障害検出により、クラスター内のノードは常に相互通信できることが保証されます。クラスターステータスのアップデートのほとんどは、小さな相違点として効率的に伝達されるため、クラスターステータス全体をノードからノードにコピーする必要性が排除されます。グレースフルに終了されたマスターは、自らが選択する後継者に明示的にその座を譲ります。これによって、完全な選出作業の必要性を排除することで、計画的なフェールオーバー時のダウンタイムを削減できます。また、数秒、数分、または数時間継続する停止の影響を効率的にシミュレーションするために、テストインフラストラクチャーを開発しました。これにより、停止が解決されるとすぐにクラスターが常に復旧することを検証できます。

Raftではない理由

なぜRaftなどの標準の分散合意アルゴリズムを単純に「プラグイン」しなかったのかという質問をよく受けます。よく知られているアルゴリズムは非常にたくさんあり、それぞれに異なる利点と欠点があります。私たちは慎重に評価し、見つけ得るすべてのドキュメントからヒントを得ました。初期の概念実証に使用したのは、Raftによく似たプロトコルでした。この経験から学んだのは、それをElasticsearchに完全に統合するためには膨大な変更が必要なことです。標準のアルゴリズムの多くは、Elasticsearchにとって最適とは言えない設計上の決定もいくつか規定しています。たとえば次のようなものです。

  • オペレーションのログに関して頻繁に構造化が行われる。それに対し、Elasticsearchのクラスターコーディネーションは、より自然にクラスターステータス自体を直接ベースとしているため、バッチ作業(関連するオペレーションを単一のブロードキャストに組み合わせる)などの重要な最適化が、オペレーションベースよりもシンプルに実行できる。
  • クラスターの拡張または縮小の機能に相当な制約があることが多く、メンテナンス作業の多くでは一連の手順が必要になる。それに対し、Elasticsearchのクラスターコーディネーションでは、1つの手順で安全に任意の再構成を実行できる。これにより、問題となる中間ステータスを回避することで、関連システムが簡素化される。
  • 安全を重視しすぎていることが多いため、稼働状態の保証方法に関する詳細が放置されており、不健全なノードが見つかった場合のクラスターによる対応方法が説明されていない。Elasticsearchの健全性チェックは複雑であり、長年にわたって現場で使用され、洗練されてきたため、既存の動作を維持することが重要。実際、システムの安全性に関するプロパティを実装するほうが、継続稼働を保証することよりも少ない工程で済んだ。実装作業の大部分は、システムの活性プロパティに重点が置かれた。
  • プロジェクトの目標の1つは、Zen Discoveryを実行しているバージョン6.7から、新しいコーディネーションサブシステムが稼働するバージョン7クラスターに、ダウンタイムなしのローリングアップグレードを実行することであったため、このようなローリングアップグレードが可能なものに、標準のアルゴリズムのいずれかを適応させるのは現実的ではないと思われた。

分散合意アルゴリズムの完全な産業対応の実装は、その開発に相当な労力が必要となり、学術的な文献が説明する内容を超えて取り組む必要があります。現実ではカスタマイゼーションが必要になることは避けられず、コーディネーションプロトコルは複雑であるため、どのようなカスタマイゼーションでもエラーが入り込むリスクが伴います。結局、エンジニアリングの観点から見ると、それらのカスタマイゼーションは新しいプロトコルを開発するのに等しいという結論に達しました。

##まとめ

Elasticsearch 7.0には、より高速で安全、かつ使いやすい新しいコーディネーションサブシステムが搭載されています。7.0は、6.7からダウンタイムなしのローリングアップグレードが可能であり、回復力のあるデータレプリケーションの基盤となります。新しいクラスターコーディネーションサブシステムを試してみる場合は、最新の7.0ベータリリースをダウンロードし、ドキュメントを参照しながら使用を開始しましょう。ぜひフィードバックもお寄せください