要約

  • RFC 3010は、長く使うクライアント名と今回の起動実体を分けた。再初期化で変わるverifier、交渉されたclientid、認証付き確認により、同じ名前だけでは古いロックを継承できなかった。
  • サーバーが状態を失うと、通常は一リース期間のgrace periodでreclaimを先に扱い、競合し得る新規ロックやI/Oを待たせた。継続は恒久権ではなく、期限のある復旧手続きだった。

再起動したサーバーの前には、二種類の記憶が並ぶ。ディスクはファイルを覚えている。クライアントも自分のロックを覚えている。しかしサーバーのロック表だけが消えている。このとき最初に届いた新規要求を通せば、ネットワーク上の到着順が過去の権利を上書きする。

2000年12月の RFC 3010 は、最初のNFSv4仕様としてこの問題を正面から扱った。ロックやopen状態を統合した以上、障害後の「覚えている」という主張にも、検査可能な形式と期限が必要になった。

重要なのはクライアント名とクライアント実体の差である。クライアントは安定したopaque idに加え、初期化のたびに変更するverifierを送る。ホスト名は機械を示せても、どの起動かは示せない。揮発性のロック記憶を持つのは抽象的な機械ではなく、その一回の実体だからだ。

SETCLIENTID はその組をRPCの認証主体と結び、サーバーは短いclientidと確認用verifierを返した。SETCLIENTID_CONFIRM が往復を閉じる。その後のclientidは状態参照を小さくするサーバー内の略号であり、世界的な身分証でも所有証書でもない。

同じopaque idが二度現れても、同じ権利とは限らない。複製された高可用設定や誤構成なら、別の機械が同じ名前を名乗り得る。NFS4ERR_CLID_INUSE はこの衝突を可視化した。文字列の一致は統合の根拠ではなく、むしろ統合してはいけない可能性の証拠だった。

認証された同じ主体が新しいverifierで戻れば、サーバーはクライアントが再初期化され、旧実体のロック記憶を失ったと判断できる。そこで旧clientidに属する状態を解放できる。ただし、verifierだけで他人のロックを消してはならない。時代の切替を示す値と、それを宣言できるprincipalは別の検査である。

もう一つの境界はleaseだった。サーバーが一つの期間を定め、通常の状態操作が全状態の期限を暗黙に更新する。何も操作しないクライアントにはRENEWがある。ロック数に比例して更新要求を増やさず、同時に無応答のクライアントが永久に他者を排除することも防いだ。

leaseを越えて更新がなければ、サーバーは状態を回収して競合を許せる。長い分断から戻ったクライアントは古いstateidに対してNFS4ERR_EXPIREDを受け得る。その通知は、クライアント側の記憶がサーバーを拘束し続けるという幻想を止め、排他性喪失をアプリケーションへ伝えるためにある。

サーバー再起動では向きが逆になる。クライアントはclientidとstateidを覚えていても、サーバーは新しい状態時代にいる。NFS4ERR_STALE_CLIENTIDとNFS4ERR_STALE_STATEIDはその断絶の領収書である。クライアントは新しいclientidを確立し、通常処理ではなく復旧へ移る。

その復旧順序がgrace periodだった。通常は一リース期間、以前のクライアントがLOCK、OPEN、CLAIM_PREVIOUSなどのreclaim形式で状態を取り戻す。単純で安全な実装は、その間の新規ロック、open、read、writeをNFS4ERR_GRACEで拒む。サーバーが生きていることと、新しい競合を裁く準備ができたことは同じではない。

この拒否は、まだ戻っていない旧保有者を守る。障害発見や再接続が遅いだけのクライアントを、新規要求が先着したという理由で敗者にしない。猶予には終点があるため、死んだクライアントへ無限の拒否権も与えない。

十分な安定記録があれば、サーバーは猶予中にも一部の新規処理を行える。ただし、後から来る正当なreclaimと衝突せず、そのreclaimを失敗させないと保証できる場合だけである。永続化されたロック数や記録は、止める範囲を狭める証拠になる。可用性は証拠により買われ、楽観だけでは買えない。

猶予後のreclaimも自動的には優先されない。再起動以後に競合ロックやI/Oを認めていないと保証できる場合に限られる。新しい事実が成立した後で、保存されなかった古い主張を遡及的に優先すれば、今度は新規側の結果を破壊する。締切は不確実性の損失を有限にした。

RFC 2624 はNFSv4の設計課題を先に整理し、RFC 3010が最初の完全なプロトコルを示した。その後 RFC 3530 が置き換え、さらに RFC 7530 がNFSv4.0を更新した。したがって、ここで扱うのは現在の設定手順ではなく、復旧権限がどう設計されたかという歴史である。

NFSv4.1の RFC 5661 はEXCHANGE_IDとsessionを導入し、後継の RFC 8881 は安定記録とreclaim許容度の交換をさらに明確にした。障害後に寛容でありたいサーバーほど、どのクライアントにどの状態があったかを長く保管しなければならない。

Lu HengのRunning-Code Primacyという視点では、権利は名前の中ではなく、再起動後のコードが検証できる連鎖にある。認証主体、起動実体、期限、回復形式、猶予窓、後発競合の不在が揃って初めて、旧状態は再構成できる。共通層は永久所有を宣言せず、障害後の先着だけで旧権利を奪えない順序を定める。

同じ名称やマウントが見えることを連続性とみなすのがStability Fallacyである。RFC 3010は消失を隠さず、staleとして公開し、新しい競合を一時停止して、証拠を再構築させた。クライアントがロックを覚えていたから残ったのではない。プロトコルが、忘却後に誰から話を聞くべきかを覚えていたのである。

Sources