CPU / TCP 開発中

1 ノードから 3、そして 10 ノードへ

単一シャードから始め、同じクライアント API でメンバーを増やします。現在の CPU/TCP 実装では運用側の調整が必要です。サーバー起動だけでは参加できず、すべての ShardedClient に完全なルートスナップショットを配布します。

実行例は 1 プロセス内の localhost TCP サーバーを 1、3、10 台に増やす機能検証です。物理 10 台、可用性、GPU 容量、性能の検証ではありません。RDMA / GDS / BlueField-3 / 実エンジンは NOT_RUN_HARDWARE です。

トポロジー

段階固定シャード IDアドレス例epoch 条件
1 ノード010.0.0.11:9735実際の初期 epoch E
3 ノード0–210.0.0.11–13:9735全ノードが前回の最大 epoch より大きい
10 ノード0–910.0.0.11–20:9735全ノードが前回の最大 epoch より大きい

アドレスは例です。実際に到達できるアドレス、独立したデータディレクトリ、安定した一意のシャード ID を使います。ID はクライアント設定です。サーバーに --shard-id、--join、シード探索、クォーラム、複製係数はありません。完全な CacheIdentity の rendezvous hash が所有者を決め、全ノードに複製しません。

ローカル実行例

クイックスタートの準備後、下記ソース版で実行します。例は一時ストアを作成し、旧サーバーの停止と join、全 epoch の更新、完全なルート置換、旧 session の拒否、各シャードの Lookup / Put / Commit / Get / Drained 解放を検証し、最後に一時ディレクトリを削除します。

cargo run -p gpucache-transport --example scaling_smoke
cargo test -p gpucache-transport --example scaling_smoke

成功した実行の出力を抜粋します。全出力では各段階の ID 0、0–2、0–9 をすべて検証します。性能測定ではなく、正しさの検証です。

status=SCALING_SMOKE_OK
topology=SINGLE_PROCESS_LOCALHOST
stage_shards=1 store_epoch=1 local_revision=1
stage_shards=3 store_epoch=2 local_revision=2
stage_shards=10 store_epoch=3 local_revision=3
per_shard_roundtrips=14
stale_sessions=REJECTED
automatic_payload_migration=NONE
durability_replication=NONE
hardware=NOT_RUN_HARDWARE
performance=NOT_A_PERFORMANCE_RESULT

1 ノードを起動

次のコマンドは単独の FileStore をループバックで起動します。公開のテスト用 fingerprint を実運用に使わず、独自の認証情報とテナントポリシーを設定してください。アプリ側で ShardedClient に ID 0、アドレス、TCP ハンドシェイクの実 epoch を設定し、lease/session API で Put と Commit の所有者を維持します。

cargo run -p gpucache-transport --bin gpucache-tcp -- serve \
  --data-dir ./data/shard-0 --bind 127.0.0.1:9735 \
  --tenant 1 --trust 1 \
  --fingerprint 0000000000000000000000000000000000000000000000000000000000000001

リモートでは隔離された信頼済みネットワークでのみ --bind 10.0.0.11:9735 --allow-remote などを使います。TLS や暗号学的ピア認証は有効にならず、fingerprint は平文 TCP の bearer 相当資格情報です。CLI はサーバーのみを起動します。

最初の段階より前にクライアントを設定

認証コンテキストと検証済みの初期エンドポイントを用意したアプリコードで、最終構成に必要な上限を設定してクライアントを作成します。replace_routes は ClientLimits を変更しません。次の設定は全段階で最大 10 シャード、各シャード 1 接続を許可します。

use gpucache_transport::{ClientLimits, ShardedClient};

let limits = ClientLimits {
    max_shards: 10,
    max_connections: 10,
    max_connections_per_shard: 1,
    max_frame_bytes: 2 * 1024 * 1024,
    ..ClientLimits::default()
};
let client = ShardedClient::new(auth, endpoints, limits)?;

シャードごとの接続上限の既定値は 4 です。そのまま max_connections だけを 3 にすると無効です。各サーバーの既定上限 16 接続は全クライアントで共有します。各クライアントプロセスには独立したプールがあるため、合計接続数を計画してください。

CLI サーバーのフレーム本体上限は 2 MiB なので、上の max_frame_bytes も同じ値です。上限はネゴシエーションされません。両端の設定を合わせてください。独立した scaling_smoke 例は、両端で一致するライブラリ既定値 1 MiB を使います。

新規クライアントのローカル revision は実 store epoch に関係なく 1 から始まります。サーバー切替を調整して完了した後、そのクライアントの現在の revision を読み、完全なスナップショットで client.replace_routes(revision, endpoints) を呼びます。revision はクライアント固有で、store epoch や共有の合意 term ではありません。

1 から 3 ノードへ

  1. 新しいシャード ID 1 と 2 を、独立ディレクトリ、同じテナント/trust ポリシー、到達可能なアドレスで準備します。最初の段階より前に選んだクライアント上限を使い、サーバー、pin、バイト、再試行枠も確認します。
  2. 全クライアントを一時停止し、新しい Lookup/Get/Put/Commit を止めます。転送完了を確認して Drained で pin を解放します。期限切れだけでは drain 完了ではありません。未完了の書き込みを完了または取消・隔離し、旧 lease を持ち越しません。
  3. 旧サーバーと全 worker を停止・join するか、読み書きを確実に防ぐ外部 fence を実施します。replace_routes はローカル状態のみを更新し、リモートを隔離しません。隔離を証明できなければ進めません。
  4. 全ディレクトリを排他的に扱い、次回ハンドシェイクの epoch が前回最大値を超えるよう準備します。旧ストアを再起動し、新ストアは必要回数初期化・再オープンします。公開前に実 epoch を確認します。
  5. ID 0、1、2 の全アドレスと実 epoch を含む完全なスナップショットを作ります。各停止中クライアントで let revision = client.stats().revision; を読み、client.replace_routes(revision, endpoints) を呼びます。拒否を処理し、差分だけを配布しないでください。必要な全クライアントが同じ完全なスナップショットを受理してから再開します。
  6. 切替後の新しい論理要求には新 session を取得します。有効な同一 epoch 内では、generation に続く Commit/Get/Release を元のシャードと epoch に固定し、generation だけの後続処理を再ルーティングしません。fence 済みの処理は破棄し、epoch を書き換えません。再配置された identity は自動移行されず、miss/エラー時は再計算して明示的に書き戻します。任意のコールド復元はホットパス外です。

新規 FileStore は epoch 1、既存ディレクトリの再オープンごとに +1 です。--epoch や管理 RPC はありません。前回最大が 1 なら新規 2 台も含め全ノードが 2 以上、7 なら全ノードが 8 以上必要です。例は排他的・有限回の再オープンを行います。実運用にも同等の調整が必要です。MANIFEST を手編集しないでください。

3 から 10 ノードへ

ID 0–9 に同じ停止 → drain → fence → epoch 準備 → 全ルート配布 → 検証 → 再開を適用します。全 1 → 全 2 の例なら次は 3 ですが、常に前回実測最大値を基準にします。クライアント作成時に確保した上限を使います。ルート交換では上限を変更できません。テナント、再試行、pin/region、フレーム、メモリ、ディスク上限をシャードごとに計画します。

クライアントは所有者に直接接続し、ShardDirectory は有界メタデータのみを保持します。所有者喪失は miss であり、複製への切替ではありません。3 台はクォーラムを意味せず、10 台は 1 万 GPU 対応を証明しません。容量・分布は実負荷で測定してください。

検証とロールバック

  • ソース commit、ID、アドレス、実 epoch、各クライアントの完全スナップショット版を記録し、ID/アドレス重複を拒否します。
  • 各シャードで Lookup → Put → Commit → Get、バイト一致、Drained 解放を検証し、別テナント/identity は hit しないことを確認します。generation はシャード内限定なので ID と epoch も保持します。
  • 旧 session/lease が拒否され、旧所有者での未完了書き込みが次期に commit できないことを確認します。所有者停止で miss/timeout → 再計算を確認します。
  • 統計、drain/quarantine/fence、論理記述子バイトと wire バイト、枠不足、再試行、接続数を観測し、CPU 回帰を実行します。実機検証の代用にはなりません。
  • 失敗時は停止を維持します。修復、または新たな停止/fence とさらに大きい epoch で旧ノード集合に戻します。旧 epoch、スナップショット、lease は復活させません。ホットデータは再計算可能です。
python3 scripts/ci/vm_regression.py --profile cpu --offline \
  --output artifacts/scaling-cpu

ソース

API の基準はリポジトリの手順と実行例です。自動クラスタ管理、オンライン再分割・移行、無停止ローリング更新、実機での本番認定は提供しません。

SCALING.md · scaling_smoke.rs · OPERATIONS.md · SECURITY.md