コンテンツにスキップ

分散ポーラー

Yagra は、ステートレスなポーラーのプールでポーリングを水平にスケールし、プローブを測定対象の機器の 近くに保ち、ネットワーク分断をまたいで監視を継続します。本ページでは、その挙動 — 割当、 フェイルオーバー、バスの保護、そして store-and-forward バッファ — を説明します。手順を追った デプロイ手引きはインストールガイドのセクション Dを 参照してください。

これらはどれも独立した「分散モード」ではありません。単一ノードのインストールでも、ここで説明する 仕組みそのままに "default" プールでポーラーが 1 台動いています。分散化とは、アーキテクチャを 変えることではなく、ポーラーとプールを増やすことです。単一ノード構成と分散構成は同じイメージで 動きます。

すべてのノードは pool 属性を持ちます(既定は "default")。ポーラーは安定した ID (YAGRA_POLLER_ID)と担当するプール(YAGRA_POLLER_POOL)で自身を識別し、バス経由で ハートビートを送ります。コアのコーディネーターはそのハートビートを追跡し、各プールのノードを 稼働中のポーラーへコンシステントハッシュで割り当てます — ポーラーが増えても失われても、プール 全体ではなく最小限の数のノードだけが再配置されます。

各ポーラーは自分の割当を作業セットとしてバス経由で受け取ります。最初にスナップショットが届き、 以後はノードの追加・移動・再割当に応じて差分が届きます。ポーラーはその作業セットからローカルに 自分のプローブをスケジュールし — コアが個々のチェックを逐一指示することはありません — 再起動後に 再接続したポーラーは完全な再同期を受け取るため、再起動をまたいでポーリングが途切れることは ありません。

障害時の扱いも同じ仕組みから導かれます。

  • ポーラーが離脱した場合 — ハートビートが止まり、コーディネーターはそのノードを同じプールで 生き残っているポーラーへ自動的にフェイルオーバーします。
  • ポーラーが参加した場合 — プールは新しい構成に合わせてリバランスし、このときも動かすのは 最小限の割合だけです。
  • プールに稼働ポーラーが 1 台もない場合 — コアは、そのプールのジョブをバス経由で個別に配信する 経路(作業セット以前からある経路)にフォールバックします。これはローリングアップグレードの 安全網です。ポーラーが再起動中のプールや、まだ前のリリースを動かしているプールも、監視が止まる ことなくノードを見続けられます。

死活と割当の状態は(オプションの)Redis ミラーに置かれ、再構築可能です — 失っても永続的なものは 何も損なわれません。プールのスケールは、同じ YAGRA_POLLER_POOL と異なる YAGRA_POLLER_ID を 持つポーラーをさらに動かすだけです。

プールの割り当てと、担当ポーラーの確認

Section titled “プールの割り当てと、担当ポーラーの確認”

ノードの実効プールは「ノード自身のプール → プールを設定している最も近い祖先フォルダ → "default"」の順に解決されます。どちらも WebUI から編集でき、ノード単体・フォルダ単体に加えて、 インベントリツリーで右クリックすると既存のプール一覧+継承+任意名の入力が出ます。重要なのは フォルダです — ツリーには複数選択が無いため、拠点まるごとのノードを一度に移す手段はフォルダ継承 だけだからです。

各選択肢には、そのプールに稼働中のポーラーがいるかが表示されます。これは見た目以上に重要です。 登録済みポーラーのいないプールにノードを割り当てると、そのジョブは誰も購読していないバスサブジェクトへ 配信され、当該ノードは黙って監視されなくなります。

逆方向の問いにはノード詳細が答えます。プールは実効プールとその由来を示し、ポーリング元は 実際に担当しているポーラーを示します(割当済み / 保留(割当が未配布)/ レガシー fan-out(上記の ポーラー 0 台時のフォールバック)/ Meraki(クラウド収集のためリング割当の対象外)/ 不明の 5 状態)。 この答えはハッシュリングから再計算するのではなく、コアが実際に配布した作業セットから読むため、 スイープが除外したノードに存在しない担当者をでっち上げることがなく、ポーラー側のノード一覧と食い違う こともありません。設定 ▸ ポーラーは逆向きに、各ポーラーの担当ノード一覧をその場で展開します。

アップグレードも同じ性質に支えられています。バスは隣接するリリース間で互換性を保つため、新しい コアは前のリリースのポーラーと問題なく動きます。まずコアを、次にポーラーをアップグレードして ください — リモート拠点も含め、1 台ずつ、順序は問いません。ポーラーはステートレスなので入れ替えの コストはなく、一時的にポーラーが居なくなったプールは、アップグレードされたポーラーが再登録するまで ジョブ単位のフォールバックで凌ぎます。手順の全体は アップグレードとバックアップにあります。

拠点に寄せる(ロケーションアフィニティ)

Section titled “拠点に寄せる(ロケーションアフィニティ)”

プールは拠点に自然に対応します。ポーラーはステートレスで、中央のバスへダイヤルアウトするため、 リモート拠点に必要なのはアウトバウンドルール 1 本だけで、インバウンドの穴は不要です — NAT や ファイアウォールの内側にあるポーラーも、手を加えずに動きます。拠点ごとにプールを 1 つ運用し (「tokyo」「osaka」、クラウドリージョンなど)、その拠点のノードを割り当てれば、プローブは拠点内に 留まります。ICMP と SNMP のトラフィックが WAN を越えることはなく、コアへ戻るのは結果・イベント・ ハートビートだけです。

受信のエッジもプールに従います。 拠点のポーラーは、その拠点のパッシブテレメトリを受け止める 場所でもあります。オプションの UDP リスナー — syslog、SNMP トラップ、NetFlow/IPFIX、sFlow — が ローカル機器の出力を受け取り、送信元ごとと全体のレート制限をエッジで適用し、同じ認証済みバスで イベントを持ち帰ります。フローのデータグラムはさらにエッジで集約されてから(固定の時間バケット、 エクスポーターごとのバイト数上位フロー)コアへ送られます。これが、繁忙な拠点のフロー量をアップリンクに 載る範囲に抑えている仕組みです。パッシブイベントはデータグラムの送信元 IP でノードに突き合わせられる ため、リモートポーラーの構成はホストネットワーク上で動きます — ブリッジの NAT はアドレスを書き換えて しまうからです。

拠点のアップリンクは、実際にそこを通るものを見込んで設計してください。ポーラーは解析済みのイベントと 並べて受信した元のバイト列も運ぶため(後から転送が、機器が送った とおりのものを中継できるようにするためです)、フローではおよそ 1,000 flows/s あたり 1 Mbit/s に なります。バーストの上限は設定リファレンスにある送信元ごと・ 全体の受信レート制限で抑えられます。

典型的なマルチ拠点構成は次のようになります。

拠点 プール ポーラー
データセンター / 本社 default コアと同居
東京支社 tokyo 支社 LAN 上にリモートで 1〜2 台
大阪支社 osaka 支社 LAN 上にリモートで 1〜2 台

各プール内では、冗長性は単なる台数です。拠点のプールでポーラーを 2 台動かせば、片方が落ちても もう片方がそのノードを引き継ぎます。上で説明した稼働ポーラーゼロ時のフォールバックはアップグレード 互換のための経路であって、拠点の冗長化ではありません — 拠点の冗長化は 2 台目のポーラーです。

1 つ特別なのが Cisco Meraki 監視で、これは拠点の機器をプローブするのではなく、組織単位で Meraki の クラウド API をポーリングします。このクラウド収集ジョブは YAGRA_MERAKI_POOL(既定は default)で指定したプールへ振り分けられます — インターネットへの外向き通信ができるプールを 指定してください。

ポーラーは WebUI の**設定 ▸ ポーラー ▸「ポーラーを登録」**から登録します。このダイアログは、 リモートポーラーが必要とする 3 つの変数 — YAGRA_POLLER_ID(安定かつ一意)、YAGRA_POLLER_POOL、 そして tls:// のバス URL — を埋めた、そのまま使える .env をリモートホスト用に生成します。これは docker-compose.poller.yml(またはネイティブバイナリの環境)にそのまま置けます。イメージも YAGRA_IMAGE_TAG でそこに固定してください。ポーラーは起動から数秒でこのページに現れ、コアは そのプールのノードを割り当て始めます。

設定 ▸ ポーラーページは、ポーリング層全体を見渡すビューでもあります。ポーラーごとに次を 表示します。

  • 死活 — 現在のステータスと、最後に受信したハートビート。
  • 割当 — 担当するプールと現在の作業セットのサイズ。プールのノードがどう分散しているかが 分かります。
  • バージョン — そのポーラーが動かしているバージョン。ロールアウトの途中で役立ちます。
  • 監視ギャップ — コアがポーラーとの連絡を失っていた直近の期間(どのポーラーか、どのプールか、 いつ、どれだけの長さか)。監視が見えていなかった時間帯が一目で分かり、メトリクスが後から 補完されたことも確認できます。

ノードはあるのに稼働ポーラーが居ないプールがあれば、警告も表示します。デプロイ手順の全体 — compose ファイル、ホストネットワーキング、受信リスナーの特権ポートに関する注意 — は インストールガイドのセクション Dにあります。

ジョブメッセージは平文のデバイス認証情報を運びます。ポーラーがプローブするのにそれを必要とするから です。単一ホストならこれで問題ありません — バスは内部の Docker ネットワークから出ないからです。 バスが信頼境界を越えてリモート拠点へ届く瞬間から、必ず先に TLS 暗号化と認証を施さなければ なりません。NATS の :4222 を平文で公開しないでください。5 つのステップからなるセットアップ — サーバー証明書、バスのパスワード、NATS の認証/TLS 設定、同居クライアントの tls:// への切り替え、 そして各拠点への公開証明書の配布 — は インストールのセクション D、ステップ 1に あります。各ポーラーは YAGRA_BUS_CA_FILE でサーバー証明書をピン留めするため、リモート拠点は システムの CA ストアではなく、ちょうど 1 つのバスエンドポイントだけを信頼します。

同梱の NATS 設定は、core ユーザーにフルアクセスを、poller ユーザーに最小権限を与えます。結果・ イベント・ハートビートの publish はでき、subscribe できるのはジョブと作業セットの割当だけです。 ただし、その限界も知っておいてください — poller アカウントは 1 つで、すべてのポーラーが共有 します。認証済みのポーラーはどのプールの割当も読めるため、この共有アカウントはポーラー群を認証しは しますが、拠点間のテナント境界ではありません。それが問題になる構成では、次に説明するポーラー 単位の認証情報スコープを使ってください。

ポーラー単位の認証情報スコープ

Section titled “ポーラー単位の認証情報スコープ”

オプションで、コアをバスの認証サービス(NATS Auth Callout)として動かし、各ポーラーに自分の プールのサブジェクトだけにスコープされた、接続ごとの認証情報を発行できます。接続時、コアは共有の ブートストラップシークレット(YAGRA_NATS_POLLER_PASSWORD)で接続してきたポーラーを検証し、その ポーラー自身の ID とプールに対応するサブジェクト — 自分のジョブストリームと自分の割当サブジェクト — だけを許可する認証情報を発行します。それ以外は何も許可しません。

その効果はこうです。侵害されたリモート拠点が見られるのは、全体に手の届く共有アカウントではなく、 自分のプールのジョブとデバイス認証情報だけになります。各ポーラーが何を読めるかは、拠点ごとに NATS サーバーの設定を編集するのではなく、接続時にコアが中央で決めます。

有効化はオプトインで、バスの TLS + 認証のセットアップと合わせて行います。

  • NATS のアカウント nkey シードをファイルとしてコアにマウントし、 YAGRA_NATS_CALLOUT_SEED_FILE でそこを指してください — シークレットはマウントしたファイルで あって、環境変数の値ではありません。
  • callout アカウントが既定($G)でない場合は YAGRA_NATS_CALLOUT_ACCOUNT を設定します。これは NATS サーバーの callout 設定で指定したアカウントと一致していなければならず、サーバー側には そのアカウントの公開鍵を YAGRA_NATS_CALLOUT_ISSUER として与える必要があります。Compose ファイルには双方のコメントアウト済みブロックが入っています。

シードファイルを設定しなければ callout レスポンダは起動せず、NATS は上記の静的アカウントに フォールバックします — 既定は無効で、有効にするまで何も変わりません。詳細は セキュリティを参照してください。

コアから切り離されたリモートポーラー — WAN 障害やファイアウォールの一時的な不調 — も監視を続けます。 ローカルで機器のポーリングを継続し、結果を捨てずに 2 段構えでバッファします。

  1. メモリ上のリングバッファ(既定で 20,000 件)。バッファリングがポーリングループを止めることは ありません。
  2. リングが埋まったときのディスクへのスピル — セグメントは /var/lib/yagra/buffer(Compose では pollerbuf ボリューム)配下に書かれるため、障害の途中でポーラーが再起動してもバッファは残ります。

バッファはあらゆる軸で上限が決まっており、溢れたときの方針はどこでも古いものから破棄なので、 ポーラーのディスクを埋め尽くすことは決してありません。

上限 既定 変数
マスタースイッチ 有効 YAGRA_STORE_FORWARDoff で無効化)
メモリ上のリング 20,000 件 YAGRA_STORE_FORWARD_MEM_MAX
ディスクスピルの合計 512 MB — 超えた分は最も古いセグメントから破棄 YAGRA_STORE_FORWARD_DISK_MAX_MB
最大保持期間 24 時間 — これより古い結果は再送時に破棄 YAGRA_STORE_FORWARD_MAX_AGE_SECS
空き容量の下限 1 GB — 空きがこれを下回るとスピルを停止 YAGRA_STORE_FORWARD_DISK_FREE_FLOOR_MB
スピルのセグメントサイズ 16 MiB — ディスク上限の粒度 YAGRA_STORE_FORWARD_SEGMENT_MB
スピル先ディレクトリ /var/lib/yagra/buffer YAGRA_STORE_FORWARD_DIR

バッファは失敗するのではなく、安全に劣化します。スピル先ディレクトリを作成も読み取りもできない 場合、ポーラーは警告をログに出し、メモリのみのバッファリングで続行します — ストレージの問題が ポーリングを落とすことはありません。

再接続すると、ポーラーは専用のバックフィルチャネル(保護されたバスでも poller アカウントに許可されて います)でバッファをまとめて再送し、コアはメトリクスを元のタイムスタンプのまま取り込みます — グラフと履歴は、偽のスパイクを作らずに障害期間を埋めます。再送が運ぶのは測定レコードそのもの、 すなわちメトリクスのサンプルとインターフェースのメタデータだけで、それ以外はありません。ディスク上で 待っているスピルにシークレットは含まれません。

アラートは決してバックフィルされません。 アラート評価は、再接続後の「今」から再開します。これは 意図的です。ドウェル時間のヒステリシスはサンプル数ベースのため、溜まった古いサンプルを再生すると 状態遷移をでっち上げ、すでに解消済みの古いアラートで埋め尽くしてしまうからです。したがって回線が 復旧しても、インシデントを再発報させることなく履歴だけが復元されます — そして回復した障害期間は それぞれ監視ギャップとして設定 ▸ ポーラーに記録されるので、誰も呼び出さなかったとしても、 見えていなかった期間は可視のまま残ります。

store-and-forward は既定で有効です。YAGRA_STORE_FORWARD=off を設定すると、素の即時送信の挙動 (バスに到達できなければ結果は破棄)に戻ります。上限値はすべて 設定リファレンスにあります。

ポーリング層は 3 つの角度から観測できます。

  • 設定 ▸ ポーラー — ポーラーごとの健全性。ステータス、プール、バージョン、作業セットのサイズ、 最後のハートビート、プールの警告、そして上で説明した直近の監視ギャップ一覧。
  • ダッシュボード — 作業セットの分布ウィジェットが、各プールのノードがポーラー間にどう散らばって いるかを示すため、偏ったプールや劣化したプールが一目で分かります。
  • Prometheus — 各ポーラーは :9100 で自身の /metrics を提供し、コアは API ポートで自身の メトリクスを提供するため、既存の監視系で監視する側を監視できます。 可観測性を参照してください。

監視ギャップの一覧と合わせると、これで運用上の問いに順番に答えられます。すべてのプールが担当されて いるか → どのノードを誰が持っているか → いつ見えていなかったのか、そしてそれは補完されたのか?