要約
- RFC 817は、相互運用性を定めるプロトコル層と、ホスト内部で処理を分担する実行モジュールを区別した。仕様上のIP/TCP境界が、最適なスケジューリング境界とは限らない。
- 分離は変更の隔離と再利用を生む一方、パケット、コピー、割り込み、コンテキスト切り替えを増やす。層を越える情報は、名前の付いた最適化に必要な最小量だけを、期限と正しいフォールバック付きで渡すべきだ。
- 最適化は実測したホットパスから始まる。通常ケースに有利なキュー、不要なコピーの削減、局所化した機種依存コードは証拠になり得るが、抽象図や珍しい障害は全体設計の根拠にならない。
待つべきかどうかは上位層が知っていた
Telnetサーバーが一文字を受け取る。TCPにはACKの義務があり、受信ウィンドウの更新もあり得る。Telnetまたはアプリケーションは文字をエコーし、制御文字ならさらに応答する。各層が自分の仕事を即座に果たすと、一つの入力から複数のパケットが送られる。
どの動作も間違ってはいない。問題は、隣の層がまもなく送信データを用意することを知らない点にあった。パケットごとの割り込み、スケジューリング、送受信処理、当時の通信料金まで、正しい分離のために繰り返し支払われる。
RFC 817が認めた連携は限定的だった。TCPは上位層がすぐにデータを返しそうかを知り、ACKを短時間だけ遅らせる。文字単位のTelnetなら、ACK、ウィンドウ、エコーを同じセグメントに収められる。しかし逆方向のデータがないファイル転送では、同じ遅延が送信者の進行を止め、スループットを下げる。
したがって上位層の意図は、TCPの権限を奪う命令ではなく、タイミングを選ぶための限定的な手掛かりである。RFC 1122は後に遅延ACKへ上限を設け、0.5秒を超えず、少なくとも完全長セグメント二つごとにACKするよう求めた。三つを一つにまとめる利益と、RTT測定やパケットクロックを乱す危険を同じ要件の中に置いたのである。
仕様の章立てはプロセス配置表ではない
デバイスドライバー、IP、TCP、その上のTelnet、FTP、SMTPという図は、どのサービスが何を提供するかを説明する。どのコードをカーネルで走らせ、どの状態をユーザープロセスが持ち、どの処理が待てるかまでは決めない。
TCP全体を一つのプロセスに置くと、カーネル変更を減らし、複雑なタイマーを通常の実行環境で扱える。ただし受信のたびにそのプロセスをスケジュールし、その後で最終アプリケーションを起こすことになる。ローカル端末やデバイスを模倣するため、結局カーネルへ戻る経路が必要になる場合もある。
カーネル内の実装は切り替えを減らし、デバイスとの統合も容易にする。一方、割り込みレベルでは通常ブロックできず、長い処理が割り込みを妨げる。到着量が処理能力を上回ると、ネットワーク処理がマシン全体を占有してもスケジューラーが抑えられない。限られたカーネル領域とOS変更への追随も、速度とは別のコストになる。
通信専用プロセッサへ移す案も境界から逃れられない。専用OSと再利用可能な実装は魅力的だが、ホストとその装置の間には、フレーミング、フロー制御、障害、通知を扱うインターフェースが必要である。その接続自体が新しいプロトコルになる。処理場所を移せば費用と障害の形は変わるが、消滅はしない。
最終宛先を知る機能がスタックを横切った
IPをカーネル、TCPを別プロセスにきれいに分けても、着信データグラムの最終宛先はTCPヘッダーを読まなければ分からない。中央TCPプロセスを一度起こして接続を選び、次にアプリケーションを起こす。仕様上の境界をそのまま実行境界にしたため、一つの機能的判断が二回の実行移行になった。
RFC 817の案は、IPとTCPの一部をカーネル側に残し、最終プロセスを識別するところまで処理することだった。データグラムを目的プロセスへ直接渡し、タイマーなどを要する残りの処理は、そのプロセスの環境で続ける。分割線はプロトコル層ではなく、デマルチプレクシングという機能に沿う。
これはネットワーク上のTCPを変えない。ピアから見える契約は同じである。変わるのは、ローカルな状態の所有、実行コンテキスト、待機能力、データ移動の回数だ。外部のレイヤーは共通の約束であり、内部モジュールはその約束を果たすための交換可能な地図だった。
同じ発想は接続ごとのTCP実装にもつながる。大容量転送向けと対話向けを分ければ、各ケースを単純化できる可能性がある。しかし修正箇所と回帰試験も増える。RFC 817自身が実験的で一般には受け入れられていない案として記しており、専門化には保守の説明責任が伴う。
良いインターフェースにも賃料がある
明確なレイヤーインターフェースは、一方を変更しても他方を壊しにくくする。複数のクライアントが同じサービスを使え、担当者がシステム全体を記憶しなくてよい。異なるホストと組織が同じインターネットに参加できるのは、この隔離があるからだ。
しかし固定されたインターフェースは意図を隠す。バイトストリームだけでは、大量ブロック転送が不向きな操作を通るかもしれない。共有メモリのないプロセス境界はカーネル経由のコピーを増やす。各層が独立に送信時刻を決めると、同居できた情報が別々のパケットになる。
RFC 817がレイヤー境界を「恩恵」と「罰」の両方として扱ったのは、モジュール性を否定するためではない。その賃料を測定可能にするためである。削減できる処理が具体的で、渡す情報が限定され、最適化がなくても正しく動くときにだけ、境界を横切る理由が成立する。
RFC 1958は後に、モジュール性の価値と性能・コストの要請を並べ、稼働実装からのフィードバックを原則論より強い証拠とした。RFC 3439は複雑性をスケーリングと運用費の問題として扱った。純粋な分離も、密結合も、それ自体では結論にならない。
六ミリ秒から一ミリ秒未満へ
Multicsでは、TCPセグメントの8ビットバイトを36ビットワードに収める配置が扱いにくかった。初期のチェックサム処理は576バイトで約六ミリ秒を要したが、マシンに強く依存した慎重な書き直しで一ミリ秒未満になった。
RFC 817は、この「汚い」方法を一般的なプログラミング様式として称賛していない。極端なボトルネックが測定され、特殊化を一つの関数に閉じ込め、結果を基準経路と照合できるから許容した。局所的な醜さに範囲と検証を与えたのである。
別の改善はもっと地味だった。次のセグメントは通常順番どおりなので、期待ケースを先に検査する。再送キューは実際の再送より、ACK済み項目の削除に頻繁に使われるため、削除を安くする。モジュール境界に合わせるだけの余分なデータコピーを避ける。
性能は一か所ではなく、チェックサム、コピー、検索、キュー、スケジューリング、状態遷移に分散して失われる。後から一つの高速化を貼り付けるのではなく、通常経路全体を観測し、境界が固定される前に積み上げなければならない。
共通の契約と私的な地図
プロトコルスタックは、相手との間で何を交換するかを答える。実装地図は、ホストがどこで時間を使い、バイトを動かし、仕事を起こし、障害を封じるかを答える。前者をそのまま後者にすると、説明図が無投票でスケジューラーになる。
RFC 817の耐久性は、境界をなくしたことではなく、二つの権限を分けた点にある。パケット数、コピー、通常ケース、例外率を測り、層を越える手掛かりの所有者、寿命、欠落時の挙動を記録する。そのうえで、別の実装が別の内部地図を選べるよう外部契約を守る。
レイヤーは相互運用のために残る。モジュールの線は実行証拠に応じて動かせる。ただしその横断は、削減する費用と新たに作る依存関係を、同じ帳簿で示さなければならない。
参照資料
会員向け解説
プロフィールの詳細
適切な会員レベルでログインすると、解説全文と出典メモをご覧いただけます。
Strategic Circle 限定
Strategic Circle
すべての読者に公開されています。参加してログインすると プロフィール解説 を閲覧できます。
Strategic Circle に参加Leadership Alliance 会員限定
Leadership Alliance
対象となる IP 資産の所有者・管理者向けです。ログインすると Leadership Alliance の解説を閲覧できます。
Leadership Alliance に参加
