百万端末のプラグインライフサイクル管理:状態・ハートビート・制御されたリリース
技術ノート
公開 / DavidHLPL
定義
本ページは、端末能力が異なり、ネットワークが揺らぎ、操作が破壊的になり得る状況で、プラグインのインストール、アップグレード、アンインストール、ルール配信を安全に収束させる方法を定義する。これは制御プレーンのモデルであり、検証済みの容量計画ではない。百万級の規模、端末能力の差、復旧動作はソースにある設計仮定である。
コアメカニズム
1. 状態機械:意図・観測・結果を分離する
端末—プラグインの各キーについて、すべてを Online/Offline 一つに押し込めず、少なくとも次の四つを保持する。
| 次元 | 意味 | 主な入力 |
|---|---|---|
desired |
ポリシーが要求するバージョン、ルール、インストール状態 | 制御プレーンのポリシー |
current |
Agent が直近に報告したバージョンと実行状態 | 集約ハートビート |
ack |
特定のインストール/更新/削除操作が実行され、受領されたか | 操作結果の応答 |
failure |
直近エラー、連続失敗回数、ブロック理由 | 応答と失敗カウンタ |
最小ループは、desired != current で候補操作を作り、能力と安全性を確認してから配信し、ack を待ち、成功時だけ current を進める。失敗時は failure を更新して再試行または遮断を選ぶ。ハートビートのタイムアウトは観測を論理的にオフラインにするだけで、アンインストール成功を意味しない。
desired <- policy
current <- heartbeat
ack, failure <- receipt(operation)
reconcile(desired, current, ack, failure)
2. マージハートビート:観測と実行を分離する
Agent は端末の身元、OS/環境、複数プラグインの状態を一度に報告する。ゲートウェイは検証とレート制限を行い、プラグインごとの観測を非同期に処理する。ハートビート処理は観測更新とスケジューリングの起点であり、インストール結果を同期的に待たない。ハートビートは破棄・縮退できるが、インストール/更新経路は安全性の防線を迂回してはならない。
ソースの容量計算は説明用の仮定である。100 万端末が 60 秒ごとに一回送るなら、統合後は約 1,000,000 / 60 ≈ 16,667 QPS、10 個のプラグインを個別送信すると約 10 倍になる。これは統合の方向を示すだけで、容量保証ではない。スレッドプールとキューは有界にし、ハートビートの滞留がサービスノードを倒さないようにする。
3. 冪等ディスパッチ:ロックは同時実行の門であり、業務事実ではない
uuid + plugin + op + targetVersion からディスパッチキーを作る。分散ロックは同時処理を防ぎ、永続化した直近操作時刻と状態は、ロック期限切れ、重複消費、ネットワーク再送をもう一度検出する。
lock:{uuid}:{plugin}:{op}:{targetVersion}
順序は、状態読取 → 直近配信の拒否 → ブラックリスト、カナリア、ブレーカ確認 → 操作記録の作成と配信 → 操作時刻更新である。同じ操作に対する重複応答は安全に識別でき、バージョンを二重に進めたり副作用を再実行したりしてはならない。具体的な操作 ID フィールドは実装時に定義すべき契約として残る。
4. カナリアとブレーカ:結果を見る前に影響範囲を制限する
| 防線 | 判定軸 | 目的 |
|---|---|---|
| 能力フィルタ | OS、バージョン、アーキテクチャ、環境、権限 | 非対応端末への配信を止める |
| カナリア | UUID、地域、組織、OS、安定 Hash の割合 | 固定した小集団で試す |
| 高リスクカナリア | カーネル、ドライバ、システム Hook の専用許可リスト | 危険なプラグインの門を高くする |
| ブレーカ | プラグイン/バージョン/操作/OS 別の失敗応答 | 後続配信を止めて通知する |
ソースの 5 分間のサンプル >= 100、失敗率 >= 20%、連続失敗 >= 30 は例示閾値であり、深刻なカーネルエラーは即時遮断し得る。割合カナリアには安定 Hash を用い、同じ端末への判定を繰り返しても結果を変えない。
5. 結果整合性と復旧
ハートビート遅延、応答の欠落、重複報告、バージョン遅延を受け入れ、各要求を強同期させずに観測を繰り返して収束させる。
- 成功の応答を受け取った後に操作ログとプラグイン状態を更新し、失敗は再試行と統計へ送る。
- ハートビートが途切れたらまず
Offlineとし、復旧のために記録を残す。保持期間後にだけ分割して削除する。 - ハートビートが戻ったら
desired/currentを比較し、まだ必要な操作だけを配信する。 - OS 非対応の組合せは TTL 付きブラックリストに入れ、同じ失敗を毎回繰り返さない。
- ブレーカ解除には明示的な運用操作または再観測期間を要求し、通常ハートビートだけで迂回させない。
適用条件
- 端末数とハートビート頻度が高く、Agent が複数プラグインの状態を集約できる。
- プラグインに長期稼働、バージョン更新、ルール更新、結果の応答が必要である。
- 制御プレーンが数秒程度の状態遅延を許容し、補償、監査、再試行の経路を持つ。
- コンテナ、root なし、読み取り専用ファイルシステム、Serverless、強化環境など、能力差に対する許可/拒否リストが必要である。
- 軽量なルール更新は長接続プッシュ、重量インストールや多段更新はスクリプトプロキシを使うなど、チャネルの前提を分けられる。
非適用とリスク
- ソースの「百万/千万級」は負荷試験結果ではない。スレッド数、キュー長、周期、保持期間は実負荷で検証する必要がある。
- 強整合性やリアルタイム可視性は保証しない。端末が恒久的に失われた場合、残せるのは保留または失敗の証拠である。
- カーネルプラグインの失敗はクラッシュ、ネットワーク断、大規模な切断を引き起こし得るため、通常のカナリアだけでは足りない。
- カナリア、ブレーカ、ブラックリスト TTL の例示値は環境をまたいで使える設定ではない。
- 永続状態、応答の冪等処理、監査を持たず分散ロックだけに依存すると、ロック期限切れ時に副作用が重複する。
最小検証
- 一つの端末から重複ハートビートを送り、観測だけが更新され未完了操作は一つであることを確認する。
- 二つのスケジューラーノードで同じ
uuid/plugin/targetVersionを処理し、一方がロックを取得し他方が観測可能な skip になることを確認する。 - 成功・重複・遅延・失敗の応答を送り、バージョンが一度だけ進み、カウンタとブレーカ統計が一致することを確認する。
- ハートビートを停止して復旧させ、
Offlineからdesired/currentに基づき補償され、確認済み操作を再実行しないことを確認する。 - カナリア命中、非命中、能力拒否、ブレーカ開の端末を試し、危険操作が遮断を迂回しないことを確認する。
証拠と不確実性
- ソース事実:
legacy-plugin-lifecycle-managementは、マージハートビート、プラグイン状態機械、ロックと時刻による二重の重複防止、能力フィルタ、安定 Hash カナリア、プラグイン版別の失敗率、処理結果の応答による完了確認、オフラインクリーンアップを記述する。 - 本ページの総合:
desired/current/ack/failureでそれらのフィールドを一つの制御プレーン語彙に揃え、「ハートビートは縮退させ、危険操作は遮断する」を境界として明示した。 - 未確認:本番負荷試験、実際の能力分布、操作 ID のワイヤ契約、閾値の校正、恒久オフライン端末の製品方針はソースにない。
関連ページ
出典と関連文書
研究記録
- 元の文書: src/content/note/ja/plugin-lifecycle-management.md
- 出典リビジョン: f49953fb0d4bd52a39bf81167b0c4b7dd7d78a64
- 証拠の状態: 有効