Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 15562] ファイルの概要

このコミットは、Go言語の標準ライブラリである net パッケージにおいて、TCP通信のベンチマークテストにIPv6のサポートを追加するものです。具体的には、既存のTCPベンチマーク関数を拡張し、IPv4だけでなくIPv6アドレスに対してもベンチマークを実行できるように変更されています。これにより、GoのネットワークスタックがIPv6環境下でどのようにパフォーマンスを発揮するかを測定・評価できるようになります。

コミット

net: add TCP over IPv6 benchmarks

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/13393fb6c7bf78a61ea3f44753396687abe2c5b5

元コミット内容

net: add TCP over IPv6 benchmarks

R=golang-dev, dave
CC=golang-dev
https://golang.org/cl/7433044

変更の背景

この変更の背景には、ネットワーク技術におけるIPv6の普及と重要性の高まりがあります。IPv4アドレスの枯渇問題が顕在化する中で、IPv6は次世代のインターネットプロトコルとして広く採用されつつあります。Go言語のようなモダンなプログラミング言語のネットワークライブラリは、IPv4とIPv6の両方を効率的かつ堅牢にサポートすることが求められます。

既存のTCPベンチマークはIPv4に限定されており、IPv6環境下でのGoのネットワークパフォーマンスを測定する手段がありませんでした。このコミットは、IPv6環境でのTCP通信の性能特性を把握し、潜在的なボトルネックや最適化の機会を特定するために、IPv6対応のベンチマークを追加することを目的としています。これにより、Goの net パッケージがIPv6環境でも期待通りの性能を発揮することを確認し、必要に応じて改善を行うための基盤が提供されます。

前提知識の解説

TCP (Transmission Control Protocol)

TCPは、インターネットプロトコルスイートの主要なプロトコルの一つで、信頼性の高い、コネクション指向のデータ転送サービスを提供します。アプリケーション層のデータがネットワークを介して正確かつ順序通りに配信されることを保証します。ストリーミングデータ、ファイル転送、ウェブブラウジングなど、多くのインターネットアプリケーションで利用されています。

IPv4 (Internet Protocol version 4)

IPv4は、インターネット上でデバイスを識別し、ルーティングを行うためのプロトコルです。32ビットのアドレスを使用し、約43億個の一意なアドレスを割り当てることができます。しかし、インターネットの急速な普及により、このアドレス空間はほぼ枯渇しています。

IPv6 (Internet Protocol version 6)

IPv6は、IPv4の後継として開発されたインターネットプロトコルです。128ビットのアドレスを使用するため、膨大な数のアドレス(約3.4×10^38個)を割り当てることができ、アドレス枯渇問題を解決します。また、IPv4と比較して、ルーティングの効率化、セキュリティ機能の強化(IPsecの内蔵)、モバイルIPのサポートなど、いくつかの改善が加えられています。IPv6アドレスは通常、: で区切られた16進数のグループで表現され、ループバックアドレスは ::1 です。

Go言語の net パッケージ

Go言語の標準ライブラリ net パッケージは、ネットワークI/Oのプリミティブを提供します。TCP/IP、UDP、IP、Unixドメインソケットなどのネットワークプロトコルをサポートし、クライアントとサーバーアプリケーションの構築を容易にします。net.Listen 関数は、指定されたネットワークアドレスで着信接続をリッスンするために使用されます。

Go言語の testing パッケージとベンチマーク

Go言語の testing パッケージは、ユニットテストとベンチマークテストの両方をサポートします。ベンチマークテストは、関数のパフォーマンスを測定するために使用され、BenchmarkXxx という命名規則に従います。*testing.B 型の引数を受け取り、b.N 回の操作を実行します。b.Skip メソッドは、特定の条件が満たされない場合にベンチマークをスキップするために使用されます。

技術的詳細

このコミットは、src/pkg/net/tcp_test.go ファイル内のTCPベンチマークテストを拡張し、IPv6のサポートを追加しています。主な変更点は以下の通りです。

  1. benchmarkTCP 関数のシグネチャ変更: 既存の benchmarkTCP 関数は、func benchmarkTCP(b *testing.B, persistent, timeout bool) でしたが、これに laddr string という新しい引数が追加され、func benchmarkTCP(b *testing.B, persistent, timeout bool, laddr string) となりました。この laddr 引数によって、ベンチマークで使用するローカルアドレス(IPv4またはIPv6)を動的に指定できるようになります。

  2. IPv6ベンチマーク関数の追加: BenchmarkTCPOneShotBenchmarkTCPOneShotTimeoutBenchmarkTCPPersistentBenchmarkTCPPersistentTimeout といった既存のIPv4ベンチマークに対応する形で、IPv6用の新しいベンチマーク関数が追加されました。これらはそれぞれ BenchmarkTCP6OneShotBenchmarkTCP6OneShotTimeoutBenchmarkTCP6PersistentBenchmarkTCP6PersistentTimeout と命名されています。

  3. IPv6アドレスの指定: 新しく追加されたIPv6ベンチマーク関数では、benchmarkTCP 関数を呼び出す際に、IPv6のループバックアドレス [::1]:0laddr 引数として渡しています。[::1] はIPv6のループバックアドレスであり、:0 は利用可能な任意のポートを意味します。

  4. IPv6サポートのチェック: IPv6ベンチマーク関数は、supportsIPv6 というグローバル変数(または同様のメカニズム)をチェックし、システムがIPv6をサポートしていない場合は b.Skip("ipv6 is not supported") を呼び出してベンチマークをスキップします。これにより、IPv6が利用できない環境でテストが失敗するのを防ぎます。

  5. net.Listen のアドレス変更: benchmarkTCP 関数内で、net.Listen("tcp", "127.0.0.1:0") とハードコードされていた部分が、新しい laddr 引数を使用するように net.Listen("tcp", laddr) に変更されました。これにより、IPv4 (127.0.0.1:0) とIPv6 ([::1]:0) の両方でリスナーを作成できるようになります。

これらの変更により、GoのネットワークスタックがIPv6環境下でどのように動作し、どの程度のパフォーマンスを発揮するかを、既存のベンチマークフレームワーク内で測定できるようになりました。

コアとなるコードの変更箇所

変更は src/pkg/net/tcp_test.go ファイルに集中しています。

--- a/src/pkg/net/tcp_test.go
+++ b/src/pkg/net/tcp_test.go
@@ -11,23 +11,51 @@ import (
 	"time"
 )
 
-func BenchmarkTCPOneShot(b *testing.B) {
-	benchmarkTCP(b, false, false)
+func BenchmarkTCP4OneShot(b *testing.B) {
+	benchmarkTCP(b, false, false, "127.0.0.1:0")
 }
 
-func BenchmarkTCPOneShotTimeout(b *testing.B) {
-	benchmarkTCP(b, false, true)
+func BenchmarkTCP4OneShotTimeout(b *testing.B) {
+	benchmarkTCP(b, false, true, "127.0.0.1:0")
 }
 
-func BenchmarkTCPPersistent(b *testing.B) {
-	benchmarkTCP(b, true, false)
+func BenchmarkTCP4Persistent(b *testing.B) {
+	benchmarkTCP(b, true, false, "127.0.0.1:0")
 }
 
-func BenchmarkTCPPersistentTimeout(b *testing.B) {
-	benchmarkTCP(b, true, true)
+func BenchmarkTCP4PersistentTimeout(b *testing.B) {
+	benchmarkTCP(b, true, true, "127.0.0.1:0")
 }
 
-func benchmarkTCP(b *testing.B, persistent, timeout bool) {
+func BenchmarkTCP6OneShot(b *testing.B) {
+	if !supportsIPv6 {
+		b.Skip("ipv6 is not supported")
+	}
+	benchmarkTCP(b, false, false, "[::1]:0")
+}
+
+func BenchmarkTCP6OneShotTimeout(b *testing.B) {
+	if !supportsIPv6 {
+		b.Skip("ipv6 is not supported")
+	}
+	benchmarkTCP(b, false, true, "[::1]:0")
+}
+
+func BenchmarkTCP6Persistent(b *testing.B) {
+	if !supportsIPv6 {
+		b.Skip("ipv6 is not supported")
+	}
+	benchmarkTCP(b, true, false, "[::1]:0")
+}
+
+func BenchmarkTCP6PersistentTimeout(b *testing.B) {
+	if !supportsIPv6 {
+		b.Skip("ipv6 is not supported")
+	}
+	benchmarkTCP(b, true, true, "[::1]:0")
+}
+
+func benchmarkTCP(b *testing.B, persistent, timeout bool, laddr string) {
 	const msgLen = 512
 	conns := b.N
 	numConcurrent := runtime.GOMAXPROCS(-1) * 16
@@ -61,7 +89,7 @@ func benchmarkTCP(b *testing.B, persistent, timeout bool) {
 		}
 		return true
 	}
-	ln, err := Listen("tcp", "127.0.0.1:0")
+	ln, err := Listen("tcp", laddr)
 	if err != nil {
 		b.Fatalf("Listen failed: %v", err)
 	}

コアとなるコードの解説

benchmarkTCP 関数の変更

元の benchmarkTCP 関数は、TCPベンチマークの共通ロジックをカプセル化していました。このコミットでは、この関数のシグネチャが以下のように変更されました。

func benchmarkTCP(b *testing.B, persistent, timeout bool, laddr string) {
    // ...
    ln, err := Listen("tcp", laddr) // 変更点
    // ...
}

新しい laddr string 引数は、リスニングするネットワークアドレスを指定するために使用されます。これにより、benchmarkTCP 関数はIPv4 ("127.0.0.1:0") とIPv6 ("[::1]:0") の両方のアドレスでリスナーを作成できるようになり、コードの再利用性が向上しました。

新しいIPv6ベンチマーク関数

IPv6ベンチマーク関数は、既存のIPv4ベンチマーク関数とほぼ同じ構造を持っていますが、benchmarkTCP を呼び出す際にIPv6のループバックアドレス [::1]:0 を渡します。

例: BenchmarkTCP6OneShot

func BenchmarkTCP6OneShot(b *testing.B) {
    if !supportsIPv6 { // IPv6サポートのチェック
        b.Skip("ipv6 is not supported")
    }
    benchmarkTCP(b, false, false, "[::1]:0") // IPv6アドレスを指定
}

supportsIPv6 の利用

supportsIPv6 は、Goの net パッケージのテストスイート内で定義されている変数で、現在のシステムがIPv6をサポートしているかどうかを示すブール値です。IPv6ベンチマーク関数は、この supportsIPv6 の値を確認し、false の場合は b.Skip を呼び出してベンチマークをスキップします。これは、IPv6が有効になっていない環境でベンチマークを実行しようとした場合に、テストが失敗するのではなく、適切にスキップされるようにするための重要なガードです。これにより、テストの堅牢性と移植性が向上します。

これらの変更により、Goの net パッケージは、IPv4とIPv6の両方でTCP通信のパフォーマンスを測定するための包括的なベンチマークスイートを持つことになります。

関連リンク

参考にした情報源リンク

  • Go言語 net パッケージ公式ドキュメント: https://pkg.go.dev/net
  • Go言語 testing パッケージ公式ドキュメント: https://pkg.go.dev/testing
  • TCP/IPに関する一般的な情報 (例: Wikipedia)
  • IPv4とIPv6に関する一般的な情報 (例: Wikipedia)
  • Go言語のベンチマークに関する記事やチュートリアル (例: Go公式ブログ、各種技術ブログ)