ケーブルを抜いて出発 — xGridのHub-Spokeトポロジー、ロール昇格、5分フェイルオーバー
Blog/
||||||

ケーブルを抜いて出発 — xGridのHub-Spokeトポロジー、ロール昇格、5分フェイルオーバー

どのSpokeでも数分でHubになれます。故障したHubは5分で交換できます。すべてのRaspberry Piにフルスタックがプリインストールされており、役割は設定ファイル1つで決まります。xGridが切断環境でトポロジー変更をどのように処理するかをご紹介します。

すでにご存じのパターン

「Hub-Spokeトポロジー」という用語を聞いたことがないかもしれませんが、毎日使っています。

任意の航空会社の路線図を開いてください。いくつかの大きなノード(成田、関西、福岡)が数十の小都市への接続を放射状に広げています。大きなノードがHub、小都市がSpokeです。すべての都市からすべての都市へ直行便を飛ばす代わりに(30都市で435路線が必要)、すべてのトラフィックが少数のハブを経由します。より少ない路線で、より多くの調整を行い、はるかに効率的です。

Comparison of point-to-point network (top) versus hub-and-spoke network (bottom) — the hub-spoke model reduces the number of connections by routing through a central node

ポイント・ツー・ポイント(上)対 Hub-and-spoke(下):中央ハブ経由のルーティングで接続数を劇的に削減。出典: Wikipedia(パブリックドメイン)

物流も同じ仕組みです。FedExはすべてをメンフィス経由でルーティングします。台北から高雄へのパッケージがまずメンフィスを経由することもあります。一見不合理ですが、集中ソートはポイント・ツー・ポイントのリレーよりも効率的です。

しかし、従来のHub-Spokeには致命的な前提があります。Hubは常にオンラインであるということです。フライトはハブ空港の再開を待てます。荷物はソーティングセンターを待てます。しかし、大量傷病者発生事案においてHubがダウンした場合、患者は待てません。

xGridのHub-Spokeは2つの重要な変更を加えています。すべてのSpokeは単なる端末ではなく、完全なシステムです。そして、どのSpokeも数分で新しいHubに昇格できます。

物理レイアウト:1つのバックボーン、複数のサテライト

xGridのデプロイメントは、Ethernetスイッチを中心に構築されたスケーラブルなトポロジーです:

                 ┌─────────────────────┐
                 │  Hub A               │
                 │  CIRS + MIRS + HIRS  │
                 │  WiFi Hotspot        │
                 │  mDNS broadcast      │
                 └──────────┬──────────┘
                            │
                  ┌─────────┴─────────┐
                  │  Ethernet Switch   │
                  └──┬────┬────┬────┬─┘
                     │    │    │    │
                  ┌──┴┐┌──┴┐┌──┴┐┌──┴┐
                  │ B ││ C ││ D ││ E │  ← Spokes
                  └───┘└───┘└───┘└───┘
                  各自がWiFiホットスポットを持つ
                  各自がフルMIRSを実行
                  各自が最新のCIRSスナップショットを保持

Hubはリソースシステム(CIRS)、臨床システム(MIRS)、在庫管理(HIRS)を実行します。SpokeはEthernetスイッチを通じてHubに接続し、それぞれMIRSを実行して自局の在庫を管理します。

設計による2つの独立したネットワーク層:ステーション間のデータ同期にはEthernet。各ステーション内の臨床業務にはWiFi。一方が故障しても他方には影響しません。

すべてのRPiは完全なシステム — ゴールデンイメージ

アーキテクチャ全体で最も重要な設計判断です。すべてのRaspberry Piにすべてがプリインストールされています。

CIRS(リソース)、MIRS(臨床)、HIRS(在庫)のすべてが各SDカードに存在します。役割はハードウェアではなく、単一の設定ファイル /etc/xgrid/role.conf で決定されます。1つのフィールドを変更すれば、SpokeがHubになります。

つまり、「Hub用ユニット」と「Spoke用ユニット」を別々にストックする必要はありません。同一の予備品をストックします。どのユニットでも他のどのユニットとも交換可能です。

段階的デプロイメント — 前方ステーションから医療センターまで

階層構成接続同時接続タブレット
医療センター1 Hub + 4 Spoke8ポートスイッチ約75
地域病院1 Hub + 3 Spoke5ポートスイッチ約60
地区病院1 Hub + 1 Spoke直接ケーブル約30
前方ステーション1台スタンドアロン不要約15

同じゴールデンイメージがすべての階層で機能します。違いはデプロイするユニット数と割り当てる役割であり、搭載するソフトウェアではありません。

切断は障害ではない — それは想定された状態

xGridでは、ネットワーク接続の喪失は臨床スタッフに見える何も引き起こしません。両システムとも完全な機能で動作を継続します。自前のデータベース、自前の臨床インターフェース、自前のタブレットステーション。

基本設計原則:すべてのSpokeは完全なシステムです。Hubは能力ではなく、調整を提供します。調整が失われても、変わるのは同期のタイミングだけです。

3フェーズ同期

フェーズ1 — 検証:Hubが各Spokeの状態を確認します。30秒以内に応答がなければスキップ。クロック整合チェックにより、両デバイスが現在時刻で一致していることを確認します。30秒以上のずれがある場合、タイムスタンプ破損防止のため同期は拒否されます。

フェーズ2 — プッシュ(HubからSpokeへ):臨床イベントが外側へ流れます。Hubは5分ごとにCIRSの完全なスナップショットを各Spokeにプッシュします。これらのスナップショットは各Spokeにローカル保存されます。最新12コピー、1時間のローリングバックアップウィンドウです。

フェーズ3 — プル(SpokeからHubへ):リソースイベントが内側へ流れます。在庫変更、血液バンク操作、手術記録、調剤ログ。

6つのコンフリクト解決戦略

戦略データ種別ロジック
両方追加バイタルサイン、引き継ぎ、調剤記録不変イベント — 両方のバージョンを保持
最新が勝つ患者基本情報タイムスタンプを比較、最新の更新が優先
Hubが勝つ登録、処方、手術記録CIRS(Hub)が権威ある情報源
両方を合算在庫数量両側の消費を合算
常にブロック血液製剤、規制物質自動解決しない — 人間の検証が必要
現場優先機器状態物理的に現場にいるオペレーターが優先

両方を合算(在庫の場合):Hubが包帯5個を消費し、Spokeが3個を消費した場合、正解は「最後に更新した方」ではなく、5 + 3 = 8個消費です。

常にブロック(血液製剤の場合):両方のステーションで同時に「発行済み」とマークされた血液ユニットは、自動ルールでは解決できません。誰かがその血液ユニットが実際にどこにあるかを物理的に確認する必要があります。

ケーブルを抜いて出発 — SpokeがHubに昇格

これはアーキテクチャ全体で最も強力な機能です。

大量傷病者発生事案で1 Hub + 3 Spokeのデプロイメントを運用しています。2時間後、指揮官が10キロ離れた第2の傷病者収容点を報告します。今すぐ機能する医療ステーションがそこに必要です。

Spokeの1つに歩いて行きます。Ethernetケーブルを抜きます。バッテリーとiPadと一緒にバッグに入れます。新しい現場に車で向かいます。電源を接続します。SSHでコマンドを1つ実行します:

sudo xgrid-promote

昇格プロセスはアトミックな状態マシンです。いずれかのステップが失敗した場合、操作全体がロールバックされ、ユニットはSpokeモードに戻ります。

成功すると、iPadが新しいWiFiネットワークに接続し、PWAを開くと、元のHubからの患者データを持つ完全に動作する医療ステーションが表示されます。データは最大5分前のものです。

Hubダウン — 5分で引き継ぎ

すべてのSpokeはHubのハートビートを30秒ごとに継続的に監視しています。3回連続の失敗(90秒の沈黙)で赤いバナーがトリガーされます:「Hub offline。」

オペレーターが判断します:どのSpokeが引き継ぐか。昇格スクリプトは latest.good スナップショットを読み込みます。これは最新の検証済みバックアップを常にポイントするシンボリックリンクです。

患者データの最大損失は5分間です。スナップショットのプッシュ間隔です。

なぜ自動昇格しないのか。切断環境では、「Hubが破壊された」と「Ethernetケーブルが緩んでいる」を区別できないからです。自動昇格は、両方がリーダーだと思い込む2つのHubを作り出すリスクがあります。これはスプリットブレイン状態です。昇格は人間の判断でなければなりません。

スプリットブレイン保護 — 信頼ではなくEpoch

Spokeが Hubに昇格するたびに、role.conf のepochカウンターがインクリメントされます。epochはすべてのスナップショット、すべてのmDNSブロードキャスト、すべての同期ハンドシェイクに埋め込まれます。

ゾンビ検出。Hub A(epoch 1)がクラッシュし、Spoke Bが昇格します(epoch 2)。後で誰かがHub Aを再接続します。起動時にネットワークをスキャンし、epoch 2をブロードキャストしているHubを発見します。自身のepoch 1より高いので、Hub Aは自動的にSpokeに降格します。

Spoke検証。Spokeが異なるepochの2つのHubを発見した場合、オレンジ色のアラートを発し、人間が曖昧さを解決するまで自動再接続を拒否します。

クラスター分離。各デプロイメントは固有の cluster_id を持ちます。Spokeは一致するcluster_idのHubのみ受け入れます。

サービスディスカバリー — ハードコードIPなし

xGridは avahi-daemon 経由のmDNS(マルチキャストDNS)を使用します。Hubが起動すると、ローカルネットワークで _xgrid-hub._tcp をブロードキャストします。Spokeはこのブロードキャストをリッスンします。有効なクラスターIDとより高いepochを持つ新しいHubを検出すると、接続先を自動更新します。

設定ファイルの更新は不要。IPアドレスの記憶も不要。ネットワークが自己記述的です。

ヘッドレス — iPadがコントロールパネル

xGridのRaspberry Piにモニターは一切ありません。キーボードもありません。すべての臨床業務はWiFi経由のPWAで行います。システム管理はSSH経由です。

各ステーションの総ハードウェア:Raspberry Pi 1台、電源ケーブル1本、Ethernetケーブル1本(スタンドアロンでない場合)。デプロイメントフットプリントはバックパックに収まるほどコンパクトです。

ステーション統合 — 拠点が撤退するとき

4つのマージモードが異なるシナリオに対応します:

  • フルマージ:すべてのデータが対象ステーションに流れる
  • パーシャルマージ:選択したリソースカテゴリのみ転送
  • バックアップインポート:ポータブルバックアップから復元
  • 緊急クローズ:完全なデータ保全を伴うステーションシャットダウン

各マージは何が移動したかを正確に記録します。この監査証跡は、災害後に必ず生じる質問に回答します:「あのステーションが撤退したとき、すべてはどこへ行ったのか。」

切断を前提とした設計

ほとんどの分散システムは「ネットワークは信頼できる」という前提から始まり、信頼できない場合の例外処理を追加します。

xGridは「ネットワークは信頼できない」という前提から始まり、たまたま機能するときに最適化します。

この反転が根本的に異なる設計を生み出します:

  • すべてのノードが完全なシステム(サーバーに依存するシンクライアントではない)
  • すべてのユニットが全ソフトウェアをプリインストール(役割は設定ファイルであり、ハードウェアバリアントではない)
  • どのSpokeもHubに昇格可能
  • 同期は定期バッチ(リアルタイムストリーミングではない)
  • コンフリクト解決はデフォルト動作(例外処理ではない)
  • 古いHubは自己降格する(epochカウンターはポリシーではなく事実だから)

ケーブルは蹴り飛ばされます。スイッチはテーブルから落とされます。Hubは被弾します。

これらのいずれも障害モードではありません。トポロジー遷移です。


関連記事: Offline-First Is Not a Fallback · ISBAR Is More Than a Handoff Format