まだよくわかってないけど途中経過をメモっておく(ツッコミ歓迎)
Nagle algorythemとは
ssh/telnet接続中に、キーを一回押しただけのデータが 1 byteだと仮定して、このデータを送るとき、IPヘッダ+TCPヘッダ= 40 bytes を足して、計41bytes送らないといけない。非効率的。
キーを20回押して、せめて計60bytesになったら送ろうよ、というのがNagle algorythem. わざとdelayさせるのでこれがゲームだとすると、どのボタンを押してもしばらく送信されない状態になる。実際はMSSとかACKとか条件があるんだけどここでは省略。
とにかく Nagleが有効だと、送信が遅れる
Nagleが無効ならすぐ送信する
これを丸暗記する。
わかってないこと
世の中の通信のどれくらいが Nagle してるのか知りたい。僕は Nagle してるのか??? これがわからない。
どっちがどっちの状態だっけ
condition | exaplain |
---|---|
TCP_NODELAY is enabled | Nagle is disabled (no delay) |
TCP_NODELAY is disabled | Nagle is enabled (delay occurs) |
TCP_NODELAYとは
一般的にwebサーバがポートを開くとき、OSレベルではソケットを開いてそれをポートにアタッチする的な感じになる(違うかも). javaでもphpでもnodejsでもOSでも大抵は実行時はC言語で書かれたコードが動いている。そのC言語でsocketを開くコードがこれ
sock = socket(AF_INET, SOCK_STREAM, 0);
apacheでもnginxでもなんでも、僕らが知らないところでこのコードが動いている(たぶん)。
このsocketは、デフォルトで TCP_NODELAY = False
つまり nagleが有効なモード(=送信が遅い)である。C言語はデフォルトでスピードよりNWの効率的な利用を目指しているといっていいのだろうか。
作ったsocketに TCP_NODELAY をわざわざ適用することで、Nagleはoffになる = すぐ送信するモードになる
setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &val, len)
C言語を書くプログラマは、ここでそのアプリケーションがゲーム向きなのか、ファイル転送向きなのか選ぶ(パケットは小さいか/リアルタイム転送が必要かどうかなど)。このオプションはjavaでもOSでも、そっち側からコントロールできるオプションがあったりする。紛らわしいのはそれぞれで名前が違って、機能もちょっと違うところだ。ぐぐってると、Cの話ばかり出てくるので混乱する。
default settings
果たして何も考えずに各OS, middlewareからtcpパケットを送ったら、それはnagleなのかどうなのか? コレが知りたいんだけど、よくわからない。
ここから恐らく永遠に未完成な記事になる
platform | default state | note |
---|---|---|
linux | ||
apache | ||
ssh |
Linux
かつては sysctlの tcp_low_latency
がそれっぽい何かだったようだがKernel 4.? からなくなった。
tcp_low_latency (Boolean; default: disabled; since Linux 2.4.21/2.6;
obsolete since Linux 4.14)
If enabled, the TCP stack makes decisions that prefer lower
latency as opposed to higher throughput. It this option is
disabled, then higher throughput is preferred. An example of
an application where this default should be changed would be a
Beowulf compute cluster. Since Linux 4.14, this file still
exists, but its value is ignored.
https://man7.org/linux/man-pages/man7/tcp.7.html
合わせて読みたい
https://m.blog.naver.com/PostView.nhn?blogId=bestdriver94&logNo=221142341347
apache
よくわからない。そもそも各middlewareにデフォルト値があると思ってるのが間違ってるのかもしれない。
見つかったのは Apache HttpClient というもののマニュアル。Apache HttpClientは、javaでcurlが叩けるようなライブラリなのかもしれない。
CoreConnectionPNames.TCP_NODELAY='http.tcp.nodelay'
https://hc.apache.org/httpcomponents-client-4.2.x/tutorial/html/connmgmt.html
http requestを送るときはtcpパケット送るので、そのときに TCP_NODELAY かどうかを選べるんだろう。これを変えると、その下で動いてるC-langが、オプションを変えてくれるんだろう。
謎は謎のまま。
ssh
よくわからんけど openssh/openssh-portable のソースをgrepしてみた。
https://github.com/openssh/openssh-portable/search?q=setsockopt
set_nodelay
という関数ないでは TCP_NODELAY をしている。
set_nodelay(int fd)
{
...
if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof opt) == -1)
set_nodelay
は以下の4ファイルで呼ばれている。
- misc.h
- channels.c
- misc.c
- packet.c
https://github.com/openssh/openssh-portable/search?q=set_nodelay
例えばここでは、 PORT_STREAMLOCAL
かどうかで nodelayを切り替えている。
if (c->host_port != PORT_STREAMLOCAL)
set_nodelay(newsock);
この意味はわからないけど、状況によって Nagle を切り替えて使っているということはわかる。
いま時点の結論(おおざっぱ)
この記事の結論として、僕らは Nagle をTCP通信ひとつずつに対して、随時 on/off 切り替えながら使っているのかもしれない。
授業料払うから、新宿あたりで誰かビール飲みながら教えてくれないかしらん。
TCP_CORKとは
TCP_NODELAYのちょっと違う版ぽい。Cでsocketのオプション入れる時に、TCP_NODELAYの代わりにいれる。
setsockopt(sock, IPPROTO_TCP, TCP_CORK, &val, sizeof(val));
この記事が素敵ぽいのであとで試してみる。
https://qiita.com/hana_shin/items/9b4f4c5e2c8e740c61bb