write() を2回呼ぶだけで、TCPが40ms止まる
ヘッダーと本文を小さな write() 2回に分けて送り、返事を待つと、CPUもネットワークも空いているのに、1往復ごとに約40ms止まることがあります。Nagleアルゴリズムも遅延ACKも、単体では正しい仕様です。2つが組み合わさると、タイマーが切れるまで互いに待ち合ってしまいます。この記事では、停止を予想し、50行のスクリプトで再現し、パケットトレースで確かめ、4つの対処を比べます。
ヘッダーと本文を小さな write() 2回に分けて送り、返事を待つと、CPUもネットワークも空いているのに、1往復ごとに約40ms止まることがあります。Nagleアルゴリズムも遅延ACKも、単体では正しい仕様です。2つが組み合わさると、タイマーが切れるまで互いに待ち合ってしまいます。この記事では、停止を予想し、50行のスクリプトで再現し、パケットトレースで確かめ、4つの対処を比べます。
TCP は、相手がいなくなったことを教えてくれません。読み取り側は永遠にブロックし、書き込み側は十数分も再送を続け、SO_KEEPALIVE は未確認のデータがあるあいだ何もしません。この記事では、root 不要の1ファイルの Linux 実験環境を作り、何もしない、keepalive、TCP_USER_TIMEOUT、アプリケーションのハートビートという順に仕組みを積み上げて、気づくまでの時間を測ります。NAT と RFC がどこに関わるかも整理します。
ヘッダーと本文を小さな write() 2回に分けて送り、返事を待つと、CPUもネットワークも空いているのに、1往復ごとに約40ms止まることがあります。Nagleアルゴリズムも遅延ACKも、単体では正しい仕様です。2つが組み合わさると、タイマーが切れるまで互いに待ち合ってしまいます。この記事では、停止を予想し、50行のスクリプトで再現し、パケットトレースで確かめ、4つの対処を比べます。
TCP は、相手がいなくなったことを教えてくれません。読み取り側は永遠にブロックし、書き込み側は十数分も再送を続け、SO_KEEPALIVE は未確認のデータがあるあいだ何もしません。この記事では、root 不要の1ファイルの Linux 実験環境を作り、何もしない、keepalive、TCP_USER_TIMEOUT、アプリケーションのハートビートという順に仕組みを積み上げて、気づくまでの時間を測ります。NAT と RFC がどこに関わるかも整理します。