RabbitMQクラスタで高可用性を実現するためのガイド

クラスタリング、クォーラムキュー、永続メッセージ、クライアントリカバリ、負荷分散、実用的なモニタリングを用いてRabbitMQのHAを構築します。

RabbitMQクラスタで高可用性を実現するためのガイド

RabbitMQの高可用性は、明確な障害に関する問いから始まります。1つのブローカーノードが消失したとき、パブリッシャー、コンシューマー、キューイングされたメッセージはどうなるのでしょうか?単一のRabbitMQノードは単一障害点になり得るため、本番システムでは通常、クラスタリング、レプリケートされたキュー、永続メッセージ、クライアントの再接続ロジックを組み合わせます。

新しいRabbitMQデプロイメントでは、クォーラムキューが標準のHA選択肢です。従来のミラーリングされたキューは長年にわたり非推奨であり、RabbitMQ 4.0で削除されました。そのため、古いクラスタ向けのレガシー専用ガイダンスとして扱ってください。

RabbitMQにおける高可用性の理解

RabbitMQにおける高可用性とは、クラスタ内の1つ以上のノードが障害を起こした場合でも、メッセージングシステムが大きな中断なく動作を継続できる能力を指します。これは、メッセージデータと設定を複数のノードにレプリケートすることで実現され、フェイルオーバー後に別のノードがキューへのサービスを継続できるようにします。

HA RabbitMQセットアップの主な目標は以下の通りです。

  • フォールトトレランス: システムは個々のノード障害に耐え、サービス全体の中断を防ぐことができます。
  • データの永続性: ノードがクラッシュしてもメッセージは失われません。
  • サービスの稼働時間: 継続的なメッセージ処理能力を維持します。

RabbitMQ HAのための基本概念

特定のHAメカニズムに飛び込む前に、いくつかの基礎的なRabbitMQの概念を理解することが不可欠です。

クラスタリング

RabbitMQクラスタは、ネットワーク経由で接続された複数のRabbitMQノードで構成されます。これらのノードは共通の状態、リソース(ユーザー、仮想ホスト、交換機、キューなど)を共有し、ワークロードを分散できます。クライアントはクラスタ内の任意のノードに接続でき、メッセージは異なるノードにあるキューにルーティングされます。

メッセージの永続性

メッセージの永続性はデータ損失を防ぐために重要です。RabbitMQでは、これは主に2つの設定によって実現されます。

  1. 永続キュー: キューを宣言する際に、durable引数をtrueに設定すると、キュー定義自体がブローカーの再起動後も存続することが保証されます。ブローカーがダウンして再起動した場合、永続キューは引き続き存在します。
  2. 永続メッセージ: メッセージをパブリッシュする際に、そのdelivery_mode2に設定すると、メッセージは永続的としてマークされます。パブリッシャー確認と組み合わせることで、パブリッシャーはRabbitMQがメッセージの責任を受け入れたことを認識できます。

警告: 真の永続性のためには、キューが永続的であることメッセージが永続的であること両方が必要です。キューが永続的でもメッセージが永続的でない場合、ブローカー再起動時にメッセージは失われます。メッセージが永続的でもキューが永続的でない場合、キュー定義が失われ、メッセージに到達できなくなります。

従来のミラーリングされたキューによるレガシーHA

従来のキューミラーリングは、RabbitMQ 3.xでクラシックキューをノード間でレプリケートしていました。これはRabbitMQ 4.xでは利用できません。古いクラスタを実行している場合、ha-modeを使用するポリシーがまだ存在する可能性がありますが、新しい設計では代わりにクォーラムキューを使用する必要があります。

キューミラーリングの仕組み

キューがミラーリングされると、1つのノードがマスターに、他のノードがミラー(またはレプリカ)に指定されます。キューに対するすべての操作(パブリッシュ、コンシューム、メッセージの追加/削除)はマスターノードを経由します。マスターはこれらの操作をすべてのミラーノードにレプリケートします。マスターノードに障害が発生すると、いずれかのミラーが新しいマスターに昇格します。

レガシー設定例

古いRabbitMQ 3.xクラスタは、ポリシーを使用してミラーリングを設定していました。

rabbitmqctl set_policy ha-all 
"^my-ha-queue-" '{"ha-mode":"all"}' --apply-to queues

主要なパラメータを分解してみましょう。

  • ha-all: ポリシーの名前。
  • "^my-ha-queue-": my-ha-queue-で始まるキュー名に一致する正規表現。このパターンに一致するキューにのみポリシーが適用されます。
  • "ha-mode":"all": この重要な引数はミラーリングの動作を指定します。
    • all: クラスタ内のすべてのノードにキューをミラーリングします。
    • exactly: 指定された数のノードにキューをミラーリングします(ha-paramsで数を定義します)。
    • nodes: 特定のノードリストにキューをミラーリングします(ha-paramsでノード名を定義します)。
  • --apply-to queues: このポリシーがキューに適用されることを指定します。

同期モード (ha-sync-mode)

ミラーリングされたキューは、異なる方法で同期できます。

  • manual(デフォルト): 新しく追加されたミラーノードは、マスターと自動的に同期しません。管理者が手動で同期をトリガーする必要があります。これは、ノード再起動時に自動同期がパフォーマンスの問題を引き起こす可能性がある大規模なキューに便利です。
  • automatic: 新しいミラーノードは、クラスタに参加するとすぐにマスターと自動的に同期します。これは一般的に管理が簡単ですが、一時的にパフォーマンスに影響を与える可能性があります。
rabbitmqctl set_policy ha-auto-sync 
"^important-queue-" '{"ha-mode":"exactly","ha-params":2,"ha-sync-mode":"automatic"}' --apply-to queues

このポリシーは、^important-queue-に一致するキューを正確に2つのノードにミラーリングし、新しいミラーは自動的に同期します。

従来のキューミラーリングの長所と短所

長所:

  • 確立されており、広く理解されています。
  • ノード障害に対する優れた耐性を提供できます。

短所:

  • パフォーマンスオーバーヘッド: すべての操作がマスターを経由するため、ボトルネックになる可能性があります。ミラーへのレプリケーションはレイテンシを追加します。
  • ネットワークパーティションの複雑さ: パーティション処理とフェイルオーバーの動作は、クォーラムキューよりも理解が困難でした。
  • データの安全性: ミラーリングされている間でも、マスター障害とフェイルオーバーの間に、プロデューサーに確認応答されたメッセージをマスターが完全にレプリケートする前に障害が発生した場合、データが失われる可能性があります。
  • 新しいノードの手動同期: ha-sync-mode: manualでは、メッセージ損失を防ぐために新しいノードを同期するための手動介入が必要です。

モダンキューによる高可用性の実現: クォーラムキュー

クォーラムキューは、データの安全性と予測可能なフェイルオーバーを目的として設計された、レプリケートされた永続キューです。Raftを使用し、従来のミラーリングされたキューの推奨される代替手段です。

クォーラムキューの仕組み

クォーラムキューはRaft合意アルゴリズムに基づいており、複数のノードにわたって一貫したログ(キューコンテンツ)を維持するための分散型でフォールトトレラントな方法を提供します。単一のマスターではなく、クォーラムキューはリーダーと複数のフォロワーで動作します。書き込み操作(メッセージのパブリッシュ)は、プロデューサーに確認応答される前に、ノードの**過半数(クォーラム)**にレプリケートされる必要があります。これにより、リーダーに障害が発生した場合でも、残りのノードから一貫した状態を回復できます。

従来のキューミラーリングに対するクォーラムキューの利点

  • より強力な永続性保証: メッセージはノードの過半数に安全にレプリケートされた後にのみ確認応答されるため、リーダー障害時のデータ損失の可能性が大幅に減少します。
  • 自動同期: すべてのレプリカは常に同期されています。新しいノードが参加したり、オフラインだったノードが復帰したりすると、手動介入なしに自動的にリーダーに追いつきます。
  • よりシンプルな設定: 複雑なha-modeha-sync-modeパラメータは不要です。レプリケーションファクターを定義するだけです。
  • 一貫した動作: ネットワークパーティション下での予測可能な動作。過半数だけが進行できるようにすることで、スプリットブレインシナリオを回避するように設計されています。

クォーラムキューの設定

クォーラムキューの作成は簡単です。x-queue-typequorumに設定してキューを宣言します。

import pika

connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
channel = connection.channel()

# 3つのレプリカを持つクォーラムキューを宣言
channel.queue_declare(
    queue='my.quorum.queue',
    durable=True,
    arguments={
        'x-queue-type': 'quorum',
        'x-quorum-initial-group-size': 3
    }
)

print("クォーラムキュー 'my.quorum.queue' が宣言されました。")

channel.close()
connection.close()

クォーラムキューの主要な引数:

  • x-queue-type: 'quorum': キューをクォーラムキューとして指定します。
  • x-quorum-initial-group-size: キューメンバーの初期数を設定します。多くのデプロイメントでは、クラスタサイズと障害許容度に応じて、3または5のメンバーを使用します。

ヒント: クォーラムキューの場合、通常は奇数のメンバー数(例:3または5)が推奨されます。3メンバーの場合、クォーラムは2ノードです。5メンバーの場合、クォーラムは3ノードです。これにより、メンバーの過半数未満が失われた場合でもキューは動作を継続できます。

クォーラムキューを使用すべき場合

クォーラムキューは、一般的に以下の場合に推奨されます。

  • ミッションクリティカルなデータ: メッセージ損失が絶対に許容されない場合。
  • 予測可能なレプリケートキュー: そのアーキテクチャは、ミラーリングされたクラシックキューよりも安全なフェイルオーバーと明確な一貫性動作を実現するように設計されています。
  • よりシンプルなHA管理: 自動同期とより強力な保証により、運用の複雑さが軽減されます。

従来のキューミラーリングは、以下の場合に依然として適している可能性があります。

  • まだ移行できないレガシーRabbitMQ 3.xシステム。
  • クォーラムキューへの計画的な移行中の一時的な互換性。

ブローカーの回復力と永続性のための戦略

キュー固有のHAメカニズムを超えて、真に回復力のあるRabbitMQデプロイメントには、より広範な戦略が不可欠です。

1. 永続メッセージと永続キュー

前述のように、すべての重要なキューがdurable=Trueで宣言され、ブローカー再起動後も存続させる必要があるすべてのメッセージがdelivery_mode=2(永続的)でパブリッシュされていることを確認してください。これは、ミラーリングやクォーラムキューに関係なく、データ永続性の絶対的なベースラインです。

2. クライアント接続処理と自動リカバリ

RabbitMQクライアントライブラリ(Python用pika、Java用amqp-clientなど)は、自動接続およびチャネルリカバリの機能を提供します。これらの機能を使用するようにクライアントを設定してください。ノードに障害が発生したり、ネットワークの瞬断が発生したりすると、クライアントは自動的に再接続を試み、チャネルを再確立し、キュー、交換機、バインディングを再宣言します。

例(pika、簡略化):

import pika

params = pika.ConnectionParameters(
    host='localhost',
    port=5672,
    credentials=pika.PlainCredentials('guest', 'guest'),
    heartbeat=60, # ハートビートを有効化
    blocked_connection_timeout=300 # ブロックされた接続を検出
)

connection = pika.BlockingConnection(params)

PikaのBlockingConnectionは、他の一部のクライアントのような透過的なトポロジリカバリモデルを提供しません。Pythonでは、接続作成、チャネルセットアップ、宣言、コンシューマー、パブリッシャー確認をリトライロジックでラップして、アプリケーションが再接続後に状態を再構築できるようにします。

3. クライアント接続の負荷分散

最適なパフォーマンスと回復力のために、クライアント接続をRabbitMQクラスタ内のすべてのアクティブノードに分散します。これは以下を使用して実現できます。

  • DNSラウンドロビン: RabbitMQホスト名に対して複数のIPアドレスを返すようにDNSを設定します。
  • 専用ロードバランサー: ハードウェアまたはソフトウェアのロードバランサー(例:HAProxy、Nginx)を使用してクライアント接続を分散します。これにより、ヘルスチェックを使用して異常なノードをローテーションから除外することもできます。
  • クライアント側接続文字列: 一部のクライアントライブラリでは、順次またはランダムに試行するホスト名のリストを指定できます。

4. モニタリングとアラート

プロアクティブなモニタリングは、高可用性を維持するために重要です。以下のための堅牢なモニタリングを実装します。

  • ノードステータス: 各RabbitMQノードのCPU、メモリ、ディスクI/O使用量。
  • RabbitMQメトリクス: キュー長、メッセージレート(パブリッシュ、コンシューム、未確認)、接続数、チャネル数、コンシューマー数。
  • クラスタヘルス: ノード接続性、ポリシー適用、キュー同期ステータス。

重要なしきい値(例:キュー長が制限を超えた、ノードオフライン、CPU使用率が高い)に対するアラートを設定し、潜在的な問題に迅速に対応できるようにします。

5. バックアップと復元戦略

HAメカニズムそのものではありませんが、堅牢なバックアップと復元戦略は**ディザスタリカバリ(DR)**にとって重要です。RabbitMQの定義(交換機、キュー、ユーザー、ポリシー)と、必要に応じてメッセージストア(ミラーリング/クォーラムキューがない場合や極端なDRシナリオの場合)を定期的にバックアップします。これにより、壊滅的なデータ損失やクラスタの破損から回復できます。

従来のキューミラーリングとクォーラムキューの選択

以下は、選択に役立つクイックガイドです。

機能 従来のキューミラーリング(クラシックキュー用) クォーラムキュー
データ安全性 弱い; マスター障害時にメッセージ損失の可能性 強い; クォーラム書き込み後にメッセージ確認応答
一貫性 パーティションでスプリットブレインを引き起こす可能性 強い(Raft); スプリットブレインを回避
レプリケーション マスター/スレーブモデル; ha-sync-modeが必要 リーダー/フォロワー(Raft); 自動同期
設定 ha-modeha-paramsha-sync-modeを使用したポリシー x-queue-type=quorumとオプションのx-quorum-initial-group-sizeを使用したキュー宣言
パフォーマンス マスターがボトルネックになる可能性 より安全なレプリケーション; ワークロードをベンチマーク
複雑さ 同期とリカバリのための運用上の複雑さが高い よりシンプル; フェイルオーバーと同期の自動処理
ユースケース レガシーシステム、重要度の低いデータ ミッションクリティカルなデータ、高い永続性要件

新しいデプロイメント、特にデータ整合性が最重要視される場合には、より強力な保証とよりシンプルな運用モデルにより、クォーラムキューが一般的に推奨される選択肢です

要点

新しいRabbitMQ HA作業では、クォーラムキュー、永続的な宣言、永続メッセージ、パブリッシャー確認、クライアント再接続ロジックを使用してください。クラスタの前にロードバランサーまたはマルチホストクライアント設定を配置し、ノードの健全性、キュー深度、未確認メッセージ、ディスクアラーム、メモリアラーム、コンシューマー数についてアラートを設定します。

まだ従来のミラーリングされたキューを実行している場合は、移行を計画してください。これらはレガシー動作であり、RabbitMQ 4.xは従来のキューミラーリングを削除しました。