SO_REUSEADDR についてのメモ

2021-07-09
TCP

Linux の Socket について調べている。SO_REUSEADDR について詳しい解説があって面白かったのでまとめ。

※これは、自分用メモなので、内容がとても雑です。

linux - How do SO_REUSEADDR and SO_REUSEPORT differ? - Stack Overflow

ポイント解説

the BSD socket implementation is the mother of all socket implementations

BSD の Socket 実装が全ての Socket 実装の母。この辺は、 Socket 通信の歴史を調べていた時にも見かけた情報。

Berkeley sockets - Wikipedia

Wikipedia にも詳しく載っていた。仕様としては Posix なのだけど、そもそもが BSD から来ているので、その実装の影響を受けていることを忘れるなと書いてあった。

There are a couple of basics you should know before we look at these two options. A TCP/UDP connection is identified by a tuple of five values:

{, , , , }

コネクションは、上の5つの値で識別される。それぞれの値が設定されるタイミングは以下の通り。

System Call
protocol socket()
src addr bind()
src port bind()
dest addr connect()
dest port connect()

SO_REUSEADDR

通常、echo サーバーなんかを自作すると、クライアント・サーバーのどちらから close された Socket は TIME-WAIT に状態になり MSL (Max Segment Length) の時間待機します。

こうなってしまうと、再度同じ Host, Port で Socket を作成しようとすると、エラーになってしまいます。そこで、Socket の設定で SO_REUSEADDR をセットしておけば、TIME-WAIT 状態の Socket が残っていても、再度 Socket が作成できるようになります。

SO_REUSEPORT

実装された時期は、Linux だと Kernel 3.9 以降のようです。上記の SO_REUSEADDR と用途としては同じように使えるのですが、 UDP などでは再利用以外の効果を期待できるようですが、あまり理解できなかった…

とても参考になったサイト&メモ

c - Why isn’t SO_LINGER option with a 0 timeout or 10 second timeout not removing sockets immediately or after 10 seconds? - Stack Overflow

SO_LINGER は TIME-WAIT の時間を設定するものじゃないよ。という話。 基本的に SO_LINGER は RST を 送りつけて Socket を強制破棄させる時に使うものなので、TCPのコンテキストを考えると使うべきじゃない。

General Information

Socket オプションの解説マニュアル。

net.ipv4.tcp_tw_recycle は廃止されました ― その危険性を理解する - Qiita

ISUCON とかで設定したことあったかなと思ったけど、もう廃止されていたし、使うべきでない(上記 RSTと同じ理屈。TCP のコンテキストに合ってない)

LinuxサーバーのTCPネットワークのパフォーマンスを決定するカーネルパラメータ – 1編 | NHN Cloud Meetup

めちゃくちゃ分かりやすくて泣いた。接続数が多すぎる場合は net.ipv4.tcp_tw_reuse 一択だ。

hard close:TCP コネクションを RST で切断する実装 - 【技術系】

RST で切断する実装をよく見かけるが、それはどうなんだね?という内容。同意。

ぜんぶTIME_WAITのせいだ! - Qiita

TIME_WAIT 関連を日本語で調べるとよく出てきた。LB用途なら recycle は駄目だということも言及されており、良さそう。

まとめ

自作 echo サーバー作る時は、 SO_REUSEADDR を設定して、なんども素早く Try & Error 出来るようにするといい。

ちなみに、TIME_WAIT は 2xMSLと書いてあったが、Linuxの場合は定数 TCP_TIMEWAIT_LEN の値で決まっていて、Ubuntu 20.04 LTS だと 60 sec だった。これは定数なので、実行時に変更することは出来ないし、するべきでもない。

https://elixir.bootlin.com/linux/v4.5/source/include/net/tcp.h#L117

Hz ってどういう単位なんだろ…