TCP window size とは
TCP ウィンドウサイズとは、クライアントやサーバ等のホストが TCP 接続する際にどのくらいのパケットを受け入れられるかを示す値です。
受信バッファとも呼ばれます。
TCP ヘッダにある Window フィールドを使って、「自分のメインメモリがどれくらいの Byte 数の通信を受け入れられるか」を相手に示す仕組みになっています。
MSS は経路途中の NW 機器が「1 パケット当たりどのくらいのサイズなら受け入れられるか」を示すのに対し、Window Size は TCP 通信の端末間が「ACK 無しにどのくらいの TCP ペイロード (MSS) を受信できるか」を示します。
以下に Window Size と MSS (≒MTU) との違いを示します。
MTU は Ethernet インタフェースの1パケットあたりの最大サイズです。MSS は TCP セグメンテーションによる分割時の最大サイズを意味しますが、これは多くの場合、MTU から計算されます。(ルータに adjust-mss の設定があるとルータによって最適なものに書き換えられる)
※ MTU と MSS の違いについては以下を参照して下さい。
一方、Window サイズはアプリケーションのプログラミングによってそのサイズが決まります。
例えば上図の場合、ファイルサービスを行うアプリケーションがパケット受信のためにどれくらいメモリにバッファを設けるかを基準に、開発者が決めます。
また、この Window サイズはパケット送受信の中で変更することができます。
つまり、アプリケーションが「もう空き容量が 1460 Byte しか無いよ」というときは Window=1460 にして送信します。受け取った相手は状況を察し、1460 Byte 以上は送らないようにします。
このように Window を動的に変化させる仕組みを窓の開け閉めになぞらえスライディングウィンドウと呼びます。
Calculated window size とは?
Window サイズは TCP ヘッダフォーマットとして 16 bit 用意されています。
単位は Byte ですので、2の16乗=64 KB 分用意されています。TCP が生まれた 1981 年においてはこの値はそんなに悪くなかったかもしれませんが、現代の技術レベルにおいては全然足りません。
1988 年でその問題が予測されていたようで、この年に RFC 1072 として TCP オプションという形で Window Scale が追加されました。
これは Window サイズを何倍するかを決める値です。
TCP syn および TCP syn/ack の際にこのオプションを付けて相手に送ることで、その TCP コネクション内の通信はその倍数分だけ Window サイズを掛け算します。
例えば TCP syn で Window Scale を 256 にして送信した場合、以降の通信で Window=250 とした場合、相手は 250 * 256 = 64,000 Bytes と解釈します。
この掛け算の結果を、Wireshark では [Calculated window size ] と表示します。
以下の例だと、"Window size value" が Window フィールドの値、"Window size scaling factor" が TCP syn 時の Window Scale の値、Calculated window size はそれらの掛け算です。
RFC 7323 にも書かれていますが、Window Scale は 2 の 14 乗が上限です。Window Size が 2 の 16 乗なのでこれと合わせて 2 の 30 乗 = 1 GBytes までを Window Size として使うことができるようになります。
Window size scaling factor: -1 (unknown) とは?
Window Scale オプションは TCP syn, syn/ack の時にしか使うことができません。
なので TCP syn や syn/ack の送受信が終わった後からパケットキャプチャを開始した場合は Window Scale が分からないので、[Window size scaling factor: -1 (unknown) ] と表示します。
Windows での受信バッファ(TCP Window Size)の設定
XP 以前はレジストリの変更により任意にサイズ変更が出来たようですが、Vista 以降は "Receive Window Auto-Tuning" 機能に一任され、利用者によるサイズ変更はできないようです。
以下の MS のブログページによると、
Window サイズの決定については 2 つの要因があるそうです。
- その通信を行うアプリケーション側からの指定(つまりプログラマによって決定)
- もしアプリケーション側からの指定が無い場合はインタフェースのリンク速度によって決定
2 については以下のルールになるそうです。
Below 1 megabits per second (Mbps): 8 kilobytes (KB)
1 Mbps to below 100 Mbps: 17 KB
100 Mbps to below 10 gigabits per second (Gbps): 64 KB
10 Gbps or higher: 128 KB
ただし、そこから前述した "Receive Window Auto-Tuning" 機能による調整が入ります。デフォルトでは Tuning-Level は [ normal ] に設定されており、このルールの値よりそれなりに大きな値を取ることが出来ます。
もし「出来る限り大きな値を取れるようにしたい!」というのであれば、Tuning-Level を [ experimental ] に設定します。
C:\> netsh interface tcp set global autotuninglevel=experimental
逆に、控えめにしたい場合は [ restricted ] , 非常に控えめにしたい場合は
[ highlyrestricted ] を使います。
C:\> netsh interface tcp set global autotuninglevel={restricted | highlyrestricted}
また、常にルール通りの固定値にしたいのであれば [ disabled ] を使います。
C:\> netsh interface tcp set global autotuninglevel=disabled
なお、MS のブログでは、これらの設定により Window Scale が以下のようになったことをレポートしています。
- experimental : Window Scale = 14
- normal : Window Scale = 8
- restricted : Window Scale = 4
- highly restricted : Window Scale = 2
- disabled : Window Scale オプション無し
Linux での受信バッファ(TCP Window Size)の設定
Linux の TCP Window Size の制御は Kernel Parameter により設定されています。
[root@localhost ~]# sysctl -a | grep rmem
net.core.rmem_default = 212992
net.core.rmem_max = 212992
net.ipv4.tcp_rmem = 4096 87380 6291456
net.ipv4.udp_rmem_min = 4096
[root@localhost ~]#
net.core.rmem_default および net.core.rmem_max が基本的に利用される Window Size です。単位は Byte で、default は初期値、max は最大値を意味します。
ですが実は Linux にも Windows のように Auto-Tuning 機能があり、この機能が無効の場合は上記2つにより決まりますが、有効の場合はこれ以外のパラメータも効いてきます。
Auto-Tuning 有効無効は net.ipv4.tcp_moderate_rcvbuf パラメータで決まります。1 が有効でデフォルトは 1 です。
[root@localhost ~]# sysctl -a | grep rcvbuf
net.ipv4.tcp_moderate_rcvbuf = 1
これが有効である場合、前述の net.ipv4.tcp_rmem や udp_rmem の設定が効いてくるわけです。
net.ipv4.tcp_rmem の値は [ min , default , max ] という並びになっています。min は最小値、default は初期値、max は最大値ですが、ややこしいことに初期値 (default) は net.core.rmem_default よりもこちらが優先なのですが、最大値 (max) は net.core.rmem_max が優先されます。
nesukeの推薦図書
以下に該当する人なら熟読することを強く推奨します。
- 周りのネットワークエンジニアよりも一歩抜き出た存在となり、価値を高めたい!
- サーバエンジニアだけどネットワークも含めた総合的なセキュリティへの理解も深めていきたい!
コメント