RAKUS Developers Blog | ラクス エンジニアブログ

株式会社ラクスのITエンジニアによる技術ブログです。

【Pacemaker】HAクラスタの運用で注意すべき「スプリットブレイン」とは?

はじめに

こんにちは。ラクスでインフラを担当しております渡邊(kw21)と申します。

今回はサーバ・アプリケーションの冗長化に今なお広く利用されているHAクラスタソフト「Pacemaker」について、
特にActive/Standby(1+1)構成クラスタで発生しうるスプリットブレインに焦点を当ててご紹介いたします。

HAクラスタとは?

HAクラスタとは「複数のコンピュータをつなげ、全体で1つのコンピュータのように振る舞わせることでシステム全体の稼働率を高める技術」のことです(LINUX-HA JAPANより引用)。HAは「High Availability」の略で日本語で高可用クラスタとも呼ばれます。

様々な開発コミュティ及びベンダーからHAクラスタソフトが提供されており、古いものでは30年ほど前から存在するパッケージもあります。

昨今では、パブリッククラウドやコンテナオーケストレーションを利用したシステム構築が主流になりつつありますが、オンプレミスな環境で冗長システムを構築する際の選択肢としてはHAクラスタもまだまだ有力な候補のひとつです。

<HAクラスタを利用して可用性を高めた例>

下図は2つのサーバでActive/Standby(1+1)構成クラスタを実装した例です。
クラスタに組み込んだサーバはクラスタノードと呼ばれ、本記事内では1号機をノード#1、2号機をノード#2と表記しています。

通常運用時はActiveノードであるノード#1へクライアントからのアクセスを受けます。

ノード#1が何らかの障害でダウンした場合、それを検知したクラスタソフトがノード#2をStandbyからActiveに切り替え、ノード#2側でクライアントからのアクセスを受けられるようにします。  

このように、Activeノードがノード#1からノード#2に切り替わることをフェイルオーバーと呼びます。   HAクラスタソフトでシステムを冗長化するとフェイルオーバーにより障害発生時のダウンタイムを最小化させることができます。  

本記事内では主にActive/Standby(1+1)構成クラスタを取り上げていますが、その他にも両現用として稼働させるActive/Active(1+1)構成や、Standbyサーバを複数用意したN+1構成など、ソフトや目的によって様々なシステム構成を選択することができます。

Pacemakerとは?

PacemakerOSSの代表的なHAクラスタソフトのひとつで、2022年2月現在はClusterLabsというコミュニティが開発提供しています。

厳密にはPacemakerとはHAクラスタソフトを構成するコンポーネントの一つであるリソース制御機能部分の名前のことなのですが、Corosyncなどの他コンポーネントを含めたクラスタソフト全体のことを指して便宜的にPacemakerと呼ばれることもあります。
HAクラスタコンポーネントとしてPacemakerと組み合わせてよく利用されるCorosyncは主にクラスタ制御機能を担っており、クラスタ内のメッセージングやクォーラム機能を提供しています。クォーラムについては後ほど詳しく紹介します。

Pacemakerで管理する対象のアプリケーションやIPアドレスのことをリソースと呼び、Active/Standby(1+1)構成クラスタではActiveになったノードでリソースが起動します。

Pacemakerには様々なアプリケーションをPacemakerリソースとして扱うためのリソースエージェント(RA)というコンポーネントも存在し、例として下記のような種々のアプリケーションをリソース登録することができます。

  • 仮想IPアドレス:各クラスタノードのローカルIPアドレスとは別に、Activeノードでのみ有効になるIPアドレスを設定できます。「virtual ip」を略して「vip」とも呼ばれます。
  • 共有ディスククラスタノードとは別のNFSサーバなどをリソースとして設定します。ActiveノードがをNFSサーバの共有領域をマウントして読み書きを行うことで、フェイルオーバーした際に新たにActiveとなったノードからも引き続きNFSサーバ上のデータを読み書きすることができます。
  • Webサーバ・DBなどのミドルウェアApachePostgreSQLなど、アプリケーションとして利用したいsystemdサービスを設定できます。ノードがActiveになると同時にリソースとして該当サービスも起動されます。

Pacemakerはクラスタノード上のリソースの起動状態を監視しており、リソース故障を検知すると設定に従ってフェイルオーバーやリソースの再起動・停止などを行います。
リソース故障とは、Pacemakerで管理されるリソースに何らかの異常が発生したことを指しており、例えば「リソース設定した共有ディスクのサーバがダウンし、マウントできなくなった」「リソース設定したPostgreSQLサービスが停止した」などの事象がこれにあたります。

また、Pacemakerのクラスタやリソースについての設定はpcsというツールを利用します。
pcsはコマンドやWebUIでPacemakerクラスタを管理するためのコンポーネントで、各種設定及びPacemakerクラスタの起動停止や状態確認の機能も提供しています。

クラスタノード間の通信とインターコネクト

クラスタノードの死活監視・リソース状態監視を行うために、クラスタに所属する各ノードは同一ネットワーク上で疎通可能な状態である必要があります。

クラスタノード間を通信させるLANのことをインターコネクト(または系間LANやハートビートなど)と呼びます。

構築するサーバやネットワークの設計方針にもよりますが、インターコネクト用のVLANを作成したり通常のLANと兼用させたりする場合もあれば、1+1構成の両サーバをLANケーブルで直接繋いで疎通させるような場合もあります。

ノード間の死活監視がインターコネクトを通して行われている以上、インターコネクトが疎通できなくなることは各ノードにとって対向ノードがダウンしたこととほぼ同義であり、インターコネクトはHAクラスタの安定稼働における大変重要な要素となっています。

例えば、インターコネクトに何らかの異常が発生しクラスタノード間の通信が切れた場合、下図のようにノード#1とノード#2はそれぞれお互いのノードの疎通が取れなくなるため、「ノード#2(または#1)がダウンした」という判定になります。

インターコネクトが単一の障害ポイントとならないよう、設計時によく考慮する必要があります。
Pacemaker/Corosyncのクラスタの場合はcorosync.confで各ノードで利用するインターコネクトの経路を設定することができ、複数の経路を指定することでインターコネクトを冗長化することもできます。

Pacemakerクラスタでノード間の通信が切れてしまった場合に各ノードはどういった挙動をとるのか、次の項で説明します。

スプリットブレインとは?

スプリットブレイン(split brain)とは、インターコネクトが切れるなどの原因でノード間の疎通が取れなくなった際にStandbyノードがActiveに切り替わることにより、同一環境内に本来複数存在してはならないActiveノードが複数発生してしまう状態のことです。
設定されているリソースの内容にもよってはデータ破損やIP競合が発生し、重大な事故に繋がる可能性があります。

下図の例ではActive/Standby(1+1)構成のPacemakerクラスタでスプリットブレインが発生し、ノード#1とノード#2両方がActiveとなり、リソースが両方のノードで起動してしまった例です。
本来1ノードからの書き込みしか無い設計だったディスクに対し、複数のノードからの書き込みが発生しデータ破損・ロストが発生してしまう可能性があります。

私自身が経験した例だと、Active/Standby(1+1)構成でノード#1のNIC故障が発生し、一時的にインターコネクトが不安定になった結果、ノード#1がActiveのままノード#2もStandbyからActiveに切り替わってしまったことがありました。

インターコネクト切断時にスプリットブレインが発生するか否かに関わる要素として、次の項ではPacemakerにおいてクォーラムという考え方で各ノードの挙動を制御する設定について紹介します。

クォーラム(定足数)とは?

HAクラスタにおけるクォーラム(quorum・定足数)とは、一言で表すと「HAクラスタとして動作できる権利を得るための、自ノードが通信できるノード数の最低数」のことです。
分かりづらいため、下図で3台構成のクラスタでの例を示します。

クラスタに所属するノード#1・#2・#3のうち、インターコネクトの異常等によりノード#1のみ疎通できなくなったとします。

この状態から「ノード#1」と「ノード#2・#3」のどちらがHAクラスタとして稼働を継続できるか、投票システムのような形で判定されます。

各ノードは「自分を含めいくつのノードと疎通ができるか」という数を認識しており、図の場合、ノード#1はノード#2・#3とは疎通できないため自分自身のみの投票数で1。ノード#2・#3はそれぞれ自分自身とお互いは疎通できるため、投票数はそれぞれ2

通常、3ノードの過半数である"2"がクォーラム(定足数)として設定されていることが多いため、クォーラムを獲得した「ノード#2・#3」側のクラスタパーティションがHAクラスタとして稼働を継続します。

その後、設定に応じてノード#1はクラスタから切り離され、ノード#2または#3がActiveとなってリソースが起動されます。

では、2ノードで構成されるActive/Standby(1+1)構成クラスタの場合はどのように判定されるでしょうか。

2ノード構成でのクォーラムの考え方とPacemakerでスプリットブレインを防ぐ仕組み

2ノード構成のクラスタの場合、そもそも過半数という図式が成り立たないため、ノード#1と#2が切り離されたとしてもどちらもクォーラムを獲得することはできません。

Pacemakerにはクォーラム無しとなった場合の挙動を設定できる「no-quorum-policy」というクラスタプロパティがあります。
no-quorum-policyでは下記の4つのポリシーを選択することができます。

  1. ignore :全リソースの管理を続行(=リソース起動状態にする)
  2. freeze :何もしない(動いてるものは動いたまま、止まってたものは止まったまま)
  3. stop (デフォルト) :全リソースを停止する
  4. suicide :影響を受けるクラスタパーティション内の全ノードを排他処理(フェンシング)する

no-quorum-policyignore以外にしておけばインターコネクト切断時にもリソースが複数ノードで重複して起動する心配は無いのですが、しかしそれではActive/Standby(1+1)構成で突発的にActiveノードがダウンした場合にも同じ挙動が適用されてしまい、Standbyが機能しなくなってしまいます。
PacemakerでActive/Standby(1+1)構成を取る場合、Activeノードがダウンした際にフェイルオーバーして新たにStandbyノード側でリソース起動させるためには、no-quorum-policyignoreに設定しておく必要があります。

一方、no-quorum-policyignoreに設定した場合、前項で紹介したようなインターコネクト断が発生した際には

  • ノード#1 :クォーラム獲得無しのためリソースは起動状態のまま
  • ノード#2 :クォーラム獲得無しのためリソースは停止状態から起動状態へ

という挙動となります。

したがって、PacemakerでActive/Standby(1+1)構成を実装する場合、障害のきっかけ次第ではスプリットブレインが発生し得る構成となります。
その上で、Pacemakerにはスプリットブレインを回避するための仕組みが複数存在します。

<スプリットブレインの発生を防ぐ仕組み>

  1. STONITH :制御不能となったノードを強制的に停止や再起動(フェンシング)させる機能です。各ノードの電源制御デバイスへのアクセスが必要です。
  2. SFEX :Activeノードが共有ディスク上にフラグを作成することで排他制御を行うリソースです。共有ディスクを使う構成で利用可能。
  3. VIPcheck :インターコネクトは別の経路で仮想IPアドレスの割当て状態を確認することで排他制御を行うリソースです。仮想IPアドレスを使う構成で利用可能。

上記の排他制御を利用せずスプリットブレインを防ぐことができなかった場合、システムとしては障害となる可能性が非常に高いと考えられます。
次の項では、スプリットブレインが発生してしまった後の対処について考えてみました。

スプリットブレイン発生後の対処

PacemakerのActive/Standby構成で、スプリットブレインが発生してしまったらどう対処すべきでしょうか。

ここではパターンとして

①:一時的にクラスタノード間通信が切断され両Activeとなってしまったが、その後再びクラスタノード間通信ができるようになった場合
②:完全にノード間の疎通が切れ、両ノードがActiveで稼働したままとなった場合

の2つについて考えてみます。

<①:両Activeとなった後、再びクラスタノード間通信ができるようになった場合>

ノード間通信が復活すると、各ノードは一時的にクラスタから切り離されていたお互いのノードを再びクラスタに組み込もうとします。
Pacemakerクラスタへの組み込みが始まりノード間の情報連携が再開すると、リソースが両方のノードで起動されてしまっていることが認識されます。

実際に弊社検証環境のPacemaker Active/Standby構成クラスタで再現させてみたところ、Pacemakerのログに以下のようなメッセージが出力されました。

(native_create_actions)  error: Resource virtual_ip is active on 2 nodes (attempting recovery)
(native_create_actions)  notice: See https://wiki.clusterlabs.org/wiki/FAQ#Resource_is_Too_Active for more information

リソースとして登録していたvirtual_ipが2ノードでアクティブとなっているので復旧を試みます、というメッセージです。

Pacemakerではリソースが複数のノードでアクティブとなった場合の挙動を「multiple-active」というオプションで設定することができます。
multiple-activeはデフォルトでは「stop_start」となっており、いったんすべてのノードでリソースを停止させた後、片方のノードで起動するという挙動となります。

つまり、一度スプリットブレインが発生してしまっても瞬時にノード間通信が復活した場合は自動でリソースが再起動し復旧するという機能が備わっています。

ただし、一時的とはいえ両ノードでリソースが起動してしまうことには変わらないため、登録しているリソースごとにクライアントやデータへの影響を考える必要があります。
また、登録しているリソースが再起動不能なタイプだと両ノードでリソース故障状態(起動できないor停止できない)となり、STONITHによるノード強制停止や手動復旧が必須となります。

<②完全にノード間の疎通が切れ、両ノードがActiveで稼働したままとなった場合>

サーバやネットワーク構成・インターコネクトの接続方式にもよりますが、スプリットブレイン対策を何もしなかった場合に起こりえるパターンです。

両ノードがActiveのまま稼働し続けているということは、本来複数ノードで起動してはならないリソースが複数ノード上でActiveとなってしまっているということです。
そして、場合によってはリソースとして設定している共有ディスクやIPアドレス競合等が故障として判定されない限り、異常な状態でクライアントからのアクセスやデータ書き込みをし続けてしまっているかもしれません。
ハードウェアとしての故障はもちろん、本来書き込みされてはならない場所・タイミングでデータが書き込まれるということは、データ不整合やロストといった重大なインシデントに発展する可能性が非常に高いです。

慎重にサービス停止を検討し、システム全体の通信の流れやデータの書き込み方式を基にデータを精査することをおすすめいたします。

※筆者は未経験です。

Pacemaker まとめ

手軽に冗長構成環境を構築できるPacemakerですが、障害発生時にどのように動作させたいか、またはどのように想定外な異常を防ぐか慎重に検討すべきポイントがいくつも存在します。

本記事でご紹介したもの以外にも、より柔軟にPacemakerクラスタを制御する設定項目が多数存在します。
開発コミュニティであるClusterLabsのドキュメントや、日本でPacemakerを含むLinux HAクラスタを普及させているLinux-HA Japanの資料をよく参照し、事故の無い安定したHAクラスタを楽しみましょう。

参考


◆TECH PLAY
techplay.jp

◆connpass
rakus.connpass.com

Copyright © RAKUS Co., Ltd. All rights reserved.