[インデックス 11166] ファイルの概要
このコミットは、Go言語の標準ライブラリであるnet
パッケージにおいて、TCPおよびUnixドメインソケットのリスニング処理を改善し、オペレーティングシステムのカーネルが提供する最大バックログ値を利用するように変更したものです。これにより、Goアプリケーションがより効率的かつ堅牢にネットワーク接続を処理できるようになります。
コミット
net
パッケージにおいて、TCPおよびUnixソケットのリスニング時にカーネルの状態を利用するように変更。
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/d3c59f6ec851bd3adccf3a989ca57dc1958a1fc7
元コミット内容
net: make use of the kernel state to listen on TCP, Unix
R=golang-dev, dave, minux.ma
CC=golang-dev
https://golang.org/cl/5545044
変更の背景
Goのnet
パッケージにおけるTCPおよびUnixソケットのリスニング処理では、listen
システムコールに渡すバックログ値が、以前は固定値(syscall.SOMAXCONN
またはUnixソケットの場合はハードコードされた8
)に設定されていました。しかし、実際のオペレーティングシステム(OS)のカーネルは、somaxconn
などのカーネルパラメータを通じて、より大きな接続キューサイズを許容する場合があります。
固定値を使用するアプローチでは、以下のような問題がありました。
- パフォーマンスの制約: カーネルがより多くの接続をキューに入れる能力を持っていても、アプリケーションがそれを活用できないため、高負荷時に接続が拒否される可能性がありました。
- OSごとの差異への非対応: 各OSがバックログの最大値を管理する方法は異なり、固定値ではこれらの差異に柔軟に対応できませんでした。
- 設定の不整合: システム管理者がカーネルの
somaxconn
値を調整しても、Goアプリケーションがその変更を認識せず、最適なパフォーマンスを発揮できない状況が生じました。
このコミットは、これらの問題を解決し、GoアプリケーションがOSのネットワーク設定に動的に適応し、システムのネットワーク処理能力を最大限に引き出すことを目的としています。これにより、特に高トラフィックな環境下での接続安定性とスループットの向上が期待されます。
前提知識の解説
このコミットを理解するためには、以下の概念を把握しておく必要があります。
- TCP/Unixソケットのリスニングと
listen
システムコール: サーバーアプリケーションがクライアントからの接続を受け入れる準備をするプロセスを「リスニング」と呼びます。このプロセスは、通常、listen
システムコールを呼び出すことで行われます。listen
システムコールは、指定されたソケットで接続要求を待ち受ける状態にし、同時に「バックログ」と呼ばれるキューの最大サイズを設定します。 - バックログ (Backlog):
listen
システムコールに渡される引数で、サーバーがaccept
システムコールで処理するのを待っている、まだ受け入れられていない接続の最大数を指定します。これは、TCPの3ウェイハンドシェイクが完了し、接続が確立されたものの、アプリケーション層でまだ処理されていない接続要求が一時的に保持されるキューのサイズを意味します。このキューが満杯になると、それ以降の接続要求はOSレベルで拒否される可能性があり、クライアント側では「Connection refused」などのエラーが発生します。 syscall.SOMAXCONN
: POSIXシステムで定義されている定数で、listen
システムコールで指定できるバックログのデフォルトの最大値を示します。多くのシステムで128に設定されていますが、これはあくまでアプリケーションが要求できる上限であり、実際のカーネルが許容する値はこれよりも大きい場合や、システム管理者が設定を変更している場合があります。- カーネルパラメータ (
sysctl
): オペレーティングシステムの動作を制御する設定値のことで、通常はsysctl
コマンドや/proc/sys
(Linuxの場合)を通じて管理されます。ネットワーク関連のカーネルパラメータには、特にリスニングバックログに関連するものとして以下があります。- Linux:
/proc/sys/net/core/somaxconn
これは、LinuxカーネルがTCPソケットのリスニングバックログキューに保持できる接続の最大数を定義します。アプリケーションがlisten
システムコールで指定したバックログ値がこのsomaxconn
値よりも大きい場合、カーネルはサイレントにsomaxconn
の値に制限します。デフォルト値は通常128ですが、Linuxカーネル5.4以降では4096に引き上げられています。 - BSD系 (Darwin/macOS, FreeBSD, NetBSD, OpenBSD):
kern.ipc.somaxconn
(FreeBSD, Darwin),kern.somaxconn
(OpenBSD) これらのパラメータも同様に、BSD系OSにおけるリスニングバックログの最大値を制御します。sysctl
コマンドを通じて値を参照・変更できます。
- Linux:
このコミットは、Goアプリケーションがこれらのカーネルパラメータを動的に読み取り、listen
システムコールに最適なバックログ値を渡すことで、OSの能力を最大限に引き出すことを目指しています。
技術的詳細
このコミットの主要な技術的変更は、Goのnet
パッケージがTCPおよびUnixソケットのリスニングバックログを決定する際に、ハードコードされた値や一般的な定数に依存するのではなく、実行中のOSのカーネルが設定している実際の最大バックログ値を利用するようにした点です。
これを実現するために、以下の設計が導入されました。
-
maxListenerBacklog()
関数の導入: 各OS(Linux、BSD系、Windows)向けに、それぞれのOSのカーネルから最大リスニングバックログ値を取得するためのmaxListenerBacklog()
関数が実装されました。- Linux (
src/pkg/net/sock_linux.go
):/proc/sys/net/core/somaxconn
という仮想ファイルから値を読み取ります。このファイルは、Linuxカーネルがネットワーク接続のバックログキューの最大サイズを管理するために使用するパラメータを公開しています。func maxListenerBacklog() int { fd, err := open("/proc/sys/net/core/somaxconn") if err != nil { return syscall.SOMAXCONN // エラー時はデフォルト値 } defer fd.close() l, ok := fd.readLine() if !ok { return syscall.SOMAXCONN // 読み取り失敗時はデフォルト値 } f := getFields(l) n, _, ok := dtoi(f[0], 0) if n == 0 || !ok { return syscall.SOMAXCONN // 変換失敗時はデフォルト値 } return n }
- BSD系 (
src/pkg/net/sock_bsd.go
): Darwin (macOS), FreeBSD, NetBSD, OpenBSD向けに実装されています。syscall.SysctlUint32
関数を使用して、kern.ipc.somaxconn
(Darwin, FreeBSD)やkern.somaxconn
(OpenBSD)といったシステムコントロール変数から値を取得します。syscall.SysctlUint32
は、カーネルのシステムコントロールインターフェースを通じて、カーネルパラメータの値を動的に取得するためのGoのシステムコールラッパーです。NetBSDには同等のカーネル状態がないため、デフォルトのsyscall.SOMAXCONN
を使用します。func maxListenerBacklog() int { var ( n uint32 err error ) switch runtime.GOOS { case "darwin", "freebsd": n, err = syscall.SysctlUint32("kern.ipc.somaxconn") case "netbsd": // NOTE: NetBSD has no somaxconn-like kernel state so far case "openbsd": n, err = syscall.SysctlUint32("kern.somaxconn") } if n == 0 || err != nil { return syscall.SOMAXCONN // エラー時はデフォルト値 } return int(n) }
- Windows (
src/pkg/net/sock_windows.go
): 現時点ではsyscall.SOMAXCONN
を返すのみで、将来的な実装がTODO
コメントとして残されています。これは、Windowsにおけるリスニングバックログの管理方法が他のOSと異なるため、別途実装が必要であることを示唆しています。func maxListenerBacklog() int { // TODO: Implement this return syscall.SOMAXCONN }
- Linux (
-
listenerBacklog
グローバル変数の導入:src/pkg/net/sock.go
にlistenerBacklog
というグローバル変数が追加され、maxListenerBacklog()
関数の結果で初期化されるようになりました。この変数は、net
パッケージ全体で利用されるリスニングバックログの推奨値となります。 -
リスニング関数での利用:
ListenTCP
(src/pkg/net/tcpsock_posix.go
) やListenUnix
(src/pkg/net/unixsock_posix.go
) などのリスニング関数内で、syscall.Listen
に渡すバックログ値が、以前の固定値やlistenBacklog()
の呼び出しから、新しく導入されたlistenerBacklog
変数に変更されました。
これらの変更により、Goアプリケーションは、各OSのネットワーク設定に合わせた最適なバックログ値を使用できるようになり、アプリケーションのネットワークパフォーマンスと安定性が向上します。特に、高負荷なサーバーアプリケーションにおいて、接続の確立がよりスムーズになり、接続拒否のエラーが減少することが期待されます。
コアとなるコードの変更箇所
このコミットでは、主に以下のファイルが変更されました。
src/pkg/net/Makefile
:- 新規追加された
sock_bsd.go
、sock_linux.go
、sock_windows.go
が、それぞれのOSのビルドターゲット(GOFILES_darwin
,GOFILES_freebsd
,GOFILES_linux
,GOFILES_netbsd
,GOFILES_openbsd
,GOFILES_windows
)に追加されました。これにより、各OSでビルドされる際に適切なソースファイルがコンパイルされるようになります。
- 新規追加された
src/pkg/net/ipsock_posix.go
:- 既存の
listenBacklog()
関数が削除されました。この関数は、以前は固定でsyscall.SOMAXCONN
を返していました。
- 既存の
src/pkg/net/sock.go
:listenerBacklog
というグローバル変数が追加されました。この変数は、maxListenerBacklog()
関数の結果で初期化されます。
var listenerBacklog = maxListenerBacklog()
src/pkg/net/sock_bsd.go
(新規ファイル):- Darwin, FreeBSD, NetBSD, OpenBSDといったBSD系のOS向けに、
maxListenerBacklog()
関数が実装されました。この関数はsyscall.SysctlUint32
を使用してカーネルパラメータからsomaxconn
の値を取得します。
- Darwin, FreeBSD, NetBSD, OpenBSDといったBSD系のOS向けに、
src/pkg/net/sock_linux.go
(新規ファイル):- Linux向けに、
maxListenerBacklog()
関数が実装されました。この関数は/proc/sys/net/core/somaxconn
ファイルから値を読み取ります。
- Linux向けに、
src/pkg/net/sock_windows.go
(新規ファイル):- Windows向けに、
maxListenerBacklog()
関数が実装されました。現時点ではsyscall.SOMAXCONN
を返します。
- Windows向けに、
src/pkg/net/tcpsock_posix.go
:ListenTCP
関数内で、syscall.Listen
に渡すバックログ値が、listenBacklog()
の呼び出しから新しく導入されたlistenerBacklog
変数に変更されました。
--- a/src/pkg/net/tcpsock_posix.go +++ b/src/pkg/net/tcpsock_posix.go @@ -249,10 +249,10 @@ func ListenTCP(net string, laddr *TCPAddr) (l *TCPListener, err error) { if err != nil { return nil, err } - errno := syscall.Listen(fd.sysfd, listenBacklog()) - if errno != nil { + err = syscall.Listen(fd.sysfd, listenerBacklog) + if err != nil { closesocket(fd.sysfd) - return nil, &OpError{"listen", "tcp", laddr, errno} + return nil, &OpError{"listen", "tcp", laddr, err} } l = new(TCPListener) l.fd = fd
src/pkg/net/unixsock_posix.go
:ListenUnix
関数内で、syscall.Listen
に渡すバックログ値が、ハードコードされた8
またはコメントアウトされたlistenBacklog()
の呼び出しからlistenerBacklog
変数に変更されました。
--- a/src/pkg/net/unixsock_posix.go +++ b/src/pkg/net/unixsock_posix.go @@ -315,7 +315,7 @@ type UnixListener struct { // ListenUnix announces on the Unix domain socket laddr and returns a Unix listener. // Net must be "unix" (stream sockets). -func ListenUnix(net string, laddr *UnixAddr) (l *UnixListener, err error) { +func ListenUnix(net string, laddr *UnixAddr) (*UnixListener, error) { if net != "unix" && net != "unixgram" && net != "unixpacket" { return nil, UnknownNetworkError(net) } @@ -326,10 +326,10 @@ func ListenUnix(net string, laddr *UnixAddr) (l *UnixListener, err error) { if err != nil { return nil, err } - e1 := syscall.Listen(fd.sysfd, 8) // listenBacklog()); - if e1 != nil { + err = syscall.Listen(fd.sysfd, listenerBacklog) + if err != nil { closesocket(fd.sysfd) - return nil, &OpError{Op: "listen", Net: "unix", Addr: laddr, Err: e1} + return nil, &OpError{Op: "listen", Net: "unix", Addr: laddr, Err: err} } return &UnixListener{fd, laddr.Name}, nil }
コアとなるコードの解説
このコミットの核心は、Goのnet
パッケージが、各OSのカーネルが設定する最大リスニングバックログ値を動的に取得し、それを利用してlisten
システムコールを実行するようになった点にあります。
具体的には、以下のメカニズムが導入されました。
-
OS固有のバックログ取得ロジックの分離:
sock_bsd.go
,sock_linux.go
,sock_windows.go
という新しいファイルが作成され、それぞれのOSに特化したmaxListenerBacklog()
関数が定義されました。これにより、OSごとのバックログ取得方法の違いがカプセル化され、コードの可読性と保守性が向上しました。- Linuxでは
/proc/sys/net/core/somaxconn
を読み取ることで、システム管理者が設定したsomaxconn
の値を直接取得します。これは、LinuxカーネルがTCP接続のバックログキューの最大サイズを管理するために使用する標準的な方法です。 - BSD系OSでは
syscall.SysctlUint32
を使用し、kern.ipc.somaxconn
などのカーネルパラメータを動的に照会します。これにより、Goアプリケーションは、システムが許容する実際のバックログ上限を正確に把握できます。 - Windowsでは現時点では
syscall.SOMAXCONN
を返すのみですが、これは将来的にWindows固有のAPIを利用して同様の機能を実現するためのプレースホルダーとなります。
- Linuxでは
-
グローバルなバックログ値の利用:
src/pkg/net/sock.go
で定義されたlistenerBacklog
グローバル変数は、プログラムの起動時に一度だけmaxListenerBacklog()
を呼び出して初期化されます。これにより、リスニングバックログ値がアプリケーション全体で一貫して利用され、かつ、OSの現在の設定を反映したものとなります。 -
リスニング処理の統一:
ListenTCP
やListenUnix
といった高レベルのリスニング関数は、もはや固定値や古いlistenBacklog()
関数に依存せず、listenerBacklog
変数を使用するようになりました。これにより、Goアプリケーションは、OSのネットワーク設定に合わせた最適なバックログ値でソケットをリスニングできるようになり、高負荷時における接続の安定性と効率が大幅に向上します。
この変更は、Goのnet
パッケージが、より「OSフレンドリー」になり、基盤となるシステムの能力を最大限に引き出すための重要なステップと言えます。これにより、Goで開発されたネットワークアプリケーションは、様々なOS環境下でより堅牢かつ高性能に動作することが期待されます。
関連リンク
- Go CL (Change List):
https://golang.org/cl/5545044
参考にした情報源リンク
- Go言語の
net
パッケージに関するドキュメント - Linuxカーネルの
net.core.somaxconn
に関するドキュメントや記事 - BSD系OSの
kern.ipc.somaxconn
に関するドキュメントや記事 - TCP/IPネットワークプログラミングに関する一般的な情報源
sysctl
コマンドに関する情報I have generated the detailed commit explanation in Markdown format, following all the specified instructions and chapter structure. I have also incorporated information from the web search to enrich the "前提知識の解説" and "技術的詳細" sections.
I will now output the generated Markdown content.
# [インデックス 11166] ファイルの概要
このコミットは、Go言語の標準ライブラリである`net`パッケージにおいて、TCPおよびUnixドメインソケットのリスニング処理を改善し、オペレーティングシステムのカーネルが提供する最大バックログ値を利用するように変更したものです。これにより、Goアプリケーションがより効率的かつ堅牢にネットワーク接続を処理できるようになります。
## コミット
`net`パッケージにおいて、TCPおよびUnixソケットのリスニング時にカーネルの状態を利用するように変更。
## GitHub上でのコミットページへのリンク
[https://github.com/golang/go/commit/d3c59f6ec851bd3adccf3a989ca57dc1958a1fc7](https://github.com/golang/go/commit/d3c59f6ec851bd3adccf3a989ca57dc1958a1fc7)
## 元コミット内容
net: make use of the kernel state to listen on TCP, Unix
R=golang-dev, dave, minux.ma CC=golang-dev https://golang.org/cl/5545044
## 変更の背景
Goの`net`パッケージにおけるTCPおよびUnixソケットのリスニング処理では、以前は`listen`システムコールに渡すバックログ値が固定値(`syscall.SOMAXCONN`またはUnixソケットの場合はハードコードされた`8`)に設定されていました。しかし、実際のオペレーティングシステム(OS)のカーネルは、`somaxconn`などのカーネルパラメータを通じて、より大きな接続キューサイズを許容する場合があります。
固定値を使用するアプローチでは、以下のような問題がありました。
1. **パフォーマンスの制約:** カーネルがより多くの接続をキューに入れる能力を持っていても、アプリケーションがそれを活用できないため、高負荷時に接続が拒否される可能性がありました。
2. **OSごとの差異への非対応:** 各OSがバックログの最大値を管理する方法は異なり、固定値ではこれらの差異に柔軟に対応できませんでした。
3. **設定の不整合:** システム管理者がカーネルの`somaxconn`値を調整しても、Goアプリケーションがその変更を認識せず、最適なパフォーマンスを発揮できない状況が生じました。
このコミットは、これらの問題を解決し、GoアプリケーションがOSのネットワーク設定に動的に適応し、システムのネットワーク処理能力を最大限に引き出すことを目的としています。これにより、特に高トラフィックな環境下での接続安定性とスループットの向上が期待されます。
## 前提知識の解説
このコミットを理解するためには、以下の概念を把握しておく必要があります。
* **TCP/Unixソケットのリスニングと`listen`システムコール:**
サーバーアプリケーションがクライアントからの接続を受け入れる準備をするプロセスを「リスニング」と呼びます。このプロセスは、通常、`listen`システムコールを呼び出すことで行われます。`listen`システムコールは、指定されたソケットで接続要求を待ち受ける状態にし、同時に「バックログ」と呼ばれるキューの最大サイズを設定します。
* **バックログ (Backlog):**
`listen`システムコールに渡される引数で、サーバーが`accept`システムコールで処理するのを待っている、まだ受け入れられていない接続の最大数を指定します。これは、TCPの3ウェイハンドシェイクが完了し、接続が確立されたものの、アプリケーション層でまだ処理されていない接続要求が一時的に保持されるキューのサイズを意味します。このキューが満杯になると、それ以降の接続要求はOSレベルで拒否される可能性があり、クライアント側では「Connection refused」などのエラーが発生します。
* **`syscall.SOMAXCONN`:**
POSIXシステムで定義されている定数で、`listen`システムコールで指定できるバックログのデフォルトの最大値を示します。多くのシステムで128に設定されていますが、これはあくまでアプリケーションが要求できる上限であり、実際のカーネルが許容する値はこれよりも大きい場合や、システム管理者が設定を変更している場合があります。
* **カーネルパラメータ (`sysctl`):**
オペレーティングシステムの動作を制御する設定値のことで、通常は`sysctl`コマンドや`/proc/sys`(Linuxの場合)を通じて管理されます。ネットワーク関連のカーネルパラメータには、特にリスニングバックログに関連するものとして以下があります。
* **Linux:** `/proc/sys/net/core/somaxconn`
これは、LinuxカーネルがTCPソケットのリスニングバックログキューに保持できる接続の最大数を定義します。アプリケーションが`listen`システムコールで指定したバックログ値がこの`somaxconn`値よりも大きい場合、カーネルはサイレントに`somaxconn`の値に制限します。デフォルト値は通常128ですが、Linuxカーネル5.4以降では4096に引き上げられています。
* **BSD系 (Darwin/macOS, FreeBSD, NetBSD, OpenBSD):** `kern.ipc.somaxconn` (FreeBSD, Darwin), `kern.somaxconn` (OpenBSD)
これらのパラメータも同様に、BSD系OSにおけるリスニングバックログの最大値を制御します。`sysctl`コマンドを通じて値を参照・変更できます。
このコミットは、Goアプリケーションがこれらのカーネルパラメータを動的に読み取り、`listen`システムコールに最適なバックログ値を渡すことで、OSの能力を最大限に引き出すことを目指しています。
## 技術的詳細
このコミットの主要な技術的変更は、Goの`net`パッケージがTCPおよびUnixソケットのリスニングバックログを決定する際に、ハードコードされた値や一般的な定数に依存するのではなく、実行中のOSのカーネルが設定している実際の最大バックログ値を利用するようにした点です。
これを実現するために、以下の設計が導入されました。
1. **`maxListenerBacklog()` 関数の導入:**
各OS(Linux、BSD系、Windows)向けに、それぞれのOSのカーネルから最大リスニングバックログ値を取得するための`maxListenerBacklog()`関数が実装されました。
* **Linux (`src/pkg/net/sock_linux.go`):**
`/proc/sys/net/core/somaxconn`という仮想ファイルから値を読み取ります。このファイルは、Linuxカーネルがネットワーク接続のバックログキューの最大サイズを管理するために使用するパラメータを公開しています。
```go
func maxListenerBacklog() int {
fd, err := open("/proc/sys/net/core/somaxconn")
if err != nil {
return syscall.SOMAXCONN // エラー時はデフォルト値
}
defer fd.close()
l, ok := fd.readLine()
if !ok {
return syscall.SOMAXCONN // 読み取り失敗時はデフォルト値
}
f := getFields(l)
n, _, ok := dtoi(f[0], 0)
if n == 0 || !ok {
return syscall.SOMAXCONN // 変換失敗時はデフォルト値
}
return n
}
```
* **BSD系 (`src/pkg/net/sock_bsd.go`):**
Darwin (macOS), FreeBSD, NetBSD, OpenBSD向けに実装されています。`syscall.SysctlUint32`関数を使用して、`kern.ipc.somaxconn`(Darwin, FreeBSD)や`kern.somaxconn`(OpenBSD)といったシステムコントロール変数から値を取得します。`syscall.SysctlUint32`は、カーネルのシステムコントロールインターフェースを通じて、カーネルパラメータの値を動的に取得するためのGoのシステムコールラッパーです。NetBSDには同等のカーネル状態がないため、デフォルトの`syscall.SOMAXCONN`を使用します。
```go
func maxListenerBacklog() int {
var (
n uint32
err error
)
switch runtime.GOOS {
case "darwin", "freebsd":
n, err = syscall.SysctlUint32("kern.ipc.somaxconn")
case "netbsd":
// NOTE: NetBSD has no somaxconn-like kernel state so far
case "openbsd":
n, err = syscall.SysctlUint32("kern.somaxconn")
}
if n == 0 || err != nil {
return syscall.SOMAXCONN // エラー時はデフォルト値
}
return int(n)
}
```
* **Windows (`src/pkg/net/sock_windows.go`):**
現時点では`syscall.SOMAXCONN`を返すのみで、将来的な実装が`TODO`コメントとして残されています。これは、Windowsにおけるリスニングバックログの管理方法が他のOSと異なるため、別途実装が必要であることを示唆しています。
```go
func maxListenerBacklog() int {
// TODO: Implement this
return syscall.SOMAXCONN
}
```
2. **`listenerBacklog` グローバル変数の導入:**
`src/pkg/net/sock.go`に`listenerBacklog`というグローバル変数が追加され、`maxListenerBacklog()`関数の結果で初期化されるようになりました。この変数は、`net`パッケージ全体で利用されるリスニングバックログの推奨値となります。
3. **リスニング関数での利用:**
`ListenTCP` (`src/pkg/net/tcpsock_posix.go`) や `ListenUnix` (`src/pkg/net/unixsock_posix.go`) などのリスニング関数内で、`syscall.Listen`に渡すバックログ値が、以前の固定値や`listenBacklog()`の呼び出しから、新しく導入された`listenerBacklog`変数に変更されました。
これらの変更により、Goアプリケーションは、各OSのネットワーク設定に合わせた最適なバックログ値を使用できるようになり、アプリケーションのネットワークパフォーマンスと安定性が向上します。特に、高負荷なサーバーアプリケーションにおいて、接続の確立がよりスムーズになり、接続拒否のエラーが減少することが期待されます。
## コアとなるコードの変更箇所
このコミットでは、主に以下のファイルが変更されました。
* **`src/pkg/net/Makefile`**:
* 新規追加された`sock_bsd.go`、`sock_linux.go`、`sock_windows.go`が、それぞれのOSのビルドターゲット(`GOFILES_darwin`, `GOFILES_freebsd`, `GOFILES_linux`, `GOFILES_netbsd`, `GOFILES_openbsd`, `GOFILES_windows`)に追加されました。これにより、各OSでビルドされる際に適切なソースファイルがコンパイルされるようになります。
* **`src/pkg/net/ipsock_posix.go`**:
* 既存の`listenBacklog()`関数が削除されました。この関数は、以前は固定で`syscall.SOMAXCONN`を返していました。
* **`src/pkg/net/sock.go`**:
* `listenerBacklog`というグローバル変数が追加されました。この変数は、`maxListenerBacklog()`関数の結果で初期化されます。
```go
var listenerBacklog = maxListenerBacklog()
```
* **`src/pkg/net/sock_bsd.go` (新規ファイル)**:
* Darwin, FreeBSD, NetBSD, OpenBSDといったBSD系のOS向けに、`maxListenerBacklog()`関数が実装されました。この関数は`syscall.SysctlUint32`を使用してカーネルパラメータから`somaxconn`の値を取得します。
* **`src/pkg/net/sock_linux.go` (新規ファイル)**:
* Linux向けに、`maxListenerBacklog()`関数が実装されました。この関数は`/proc/sys/net/core/somaxconn`ファイルから値を読み取ります。
* **`src/pkg/net/sock_windows.go` (新規ファイル)**:
* Windows向けに、`maxListenerBacklog()`関数が実装されました。現時点では`syscall.SOMAXCONN`を返します。
* **`src/pkg/net/tcpsock_posix.go`**:
* `ListenTCP`関数内で、`syscall.Listen`に渡すバックログ値が、`listenBacklog()`の呼び出しから新しく導入された`listenerBacklog`変数に変更されました。
```diff
--- a/src/pkg/net/tcpsock_posix.go
+++ b/src/pkg/net/tcpsock_posix.go
@@ -249,10 +249,10 @@ func ListenTCP(net string, laddr *TCPAddr) (l *TCPListener, err error) {
if err != nil {
return nil, err
}
- errno := syscall.Listen(fd.sysfd, listenBacklog())
- if errno != nil {
+ err = syscall.Listen(fd.sysfd, listenerBacklog)
+ if err != nil {
closesocket(fd.sysfd)
- return nil, &OpError{"listen", "tcp", laddr, errno}
+ return nil, &OpError{"listen", "tcp", laddr, err}
}
l = new(TCPListener)
l.fd = fd
```
* **`src/pkg/net/unixsock_posix.go`**:
* `ListenUnix`関数内で、`syscall.Listen`に渡すバックログ値が、ハードコードされた`8`またはコメントアウトされた`listenBacklog()`の呼び出しから`listenerBacklog`変数に変更されました。
```diff
--- a/src/pkg/net/unixsock_posix.go
+++ b/src/pkg/net/unixsock_posix.go
@@ -315,7 +315,7 @@ type UnixListener struct {
// ListenUnix announces on the Unix domain socket laddr and returns a Unix listener.
// Net must be "unix" (stream sockets).
-func ListenUnix(net string, laddr *UnixAddr) (l *UnixListener, err error) {
+func ListenUnix(net string, laddr *UnixAddr) (*UnixListener, error) {
if net != "unix" && net != "unixgram" && net != "unixpacket" {
return nil, UnknownNetworkError(net)
}
@@ -326,10 +326,10 @@ func ListenUnix(net string, laddr *UnixAddr) (l *UnixListener, err error) {
if err != nil {
return nil, err
}
- e1 := syscall.Listen(fd.sysfd, 8) // listenBacklog());
- if e1 != nil {
+ err = syscall.Listen(fd.sysfd, listenerBacklog)
+ if err != nil {
closesocket(fd.sysfd)
- return nil, &OpError{Op: "listen", Net: "unix", Addr: laddr, Err: e1}
+ return nil, &OpError{Op: "listen", Net: "unix", Addr: laddr, Err: err}
}
return &UnixListener{fd, laddr.Name}, nil
}
```
## コアとなるコードの解説
このコミットの核心は、Goの`net`パッケージが、各OSのカーネルが設定する最大リスニングバックログ値を動的に取得し、それを利用して`listen`システムコールを実行するようになった点にあります。
具体的には、以下のメカニズムが導入されました。
1. **OS固有のバックログ取得ロジックの分離:**
`sock_bsd.go`, `sock_linux.go`, `sock_windows.go`という新しいファイルが作成され、それぞれのOSに特化した`maxListenerBacklog()`関数が定義されました。これにより、OSごとのバックログ取得方法の違いがカプセル化され、コードの可読性と保守性が向上しました。
* Linuxでは`/proc/sys/net/core/somaxconn`を読み取ることで、システム管理者が設定した`somaxconn`の値を直接取得します。これは、LinuxカーネルがTCP接続のバックログキューの最大サイズを管理するために使用する標準的な方法です。
* BSD系OSでは`syscall.SysctlUint32`を使用し、`kern.ipc.somaxconn`などのカーネルパラメータを動的に照会します。これにより、Goアプリケーションは、システムが許容する実際のバックログ上限を正確に把握できます。
* Windowsでは現時点では`syscall.SOMAXCONN`を返すのみですが、これは将来的にWindows固有のAPIを利用して同様の機能を実現するためのプレースホルダーとなります。
2. **グローバルなバックログ値の利用:**
`src/pkg/net/sock.go`で定義された`listenerBacklog`グローバル変数は、プログラムの起動時に一度だけ`maxListenerBacklog()`を呼び出して初期化されます。これにより、リスニングバックログ値がアプリケーション全体で一貫して利用され、かつ、OSの現在の設定を反映したものとなります。
3. **リスニング処理の統一:**
`ListenTCP`や`ListenUnix`といった高レベルのリスニング関数は、もはや固定値や古い`listenBacklog()`関数に依存せず、`listenerBacklog`変数を使用するようになりました。これにより、Goアプリケーションは、OSのネットワーク設定に合わせた最適なバックログ値でソケットをリスニングできるようになり、高負荷時における接続の安定性と効率が大幅に向上します。
この変更は、Goの`net`パッケージが、より「OSフレンドリー」になり、基盤となるシステムの能力を最大限に引き出すための重要なステップと言えます。これにより、Goで開発されたネットワークアプリケーションは、様々なOS環境下でより堅牢かつ高性能に動作することが期待されます。
## 関連リンク
* Go CL (Change List): `https://golang.org/cl/5545044`
## 参考にした情報源リンク
* Go言語の`net`パッケージに関するドキュメント
* Linuxカーネルの`net.core.somaxconn`に関するドキュメントや記事
* BSD系OSの`kern.ipc.somaxconn`に関するドキュメントや記事
* TCP/IPネットワークプログラミングに関する一般的な情報源
* `sysctl`コマンドに関する情報