[インデックス 19628] ファイルの概要
このコミットは、Go言語の標準ライブラリである net/http
パッケージのテストファイル src/pkg/net/http/serve_test.go
に、TLS (Transport Layer Security) を使用したHTTPクライアントとサーバー間の並列ベンチマークを追加するものです。これにより、TLSが有効な状態でのHTTP通信のパフォーマンスを測定できるようになります。
コミット
commit 8c8bf3cc760e3cb806d94e2bf9a58664b8953108
Author: Dmitriy Vyukov <dvyukov@google.com>
Date: Fri Jun 27 18:30:09 2014 -0700
net/http: add TLS benchmark
R=golang-codereviews, bradfitz
CC=golang-codereviews
https://golang.org/cl/110080045
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/8c8bf3cc760e3cb806d94e2bf9a58664b8953108
元コミット内容
net/http: add TLS benchmark
R=golang-codereviews, bradfitz
CC=golang-codereviews
https://golang.org/cl/110080045
変更の背景
Go言語の net/http
パッケージは、WebアプリケーションやAPIサーバーを構築する上で非常に重要なコンポーネントです。HTTP通信において、セキュリティは不可欠であり、TLS(旧SSL)はそのための標準的なプロトコルです。TLSは通信の暗号化、認証、データの完全性を提供しますが、その処理には計算コストが伴います。
このコミットが作成された背景には、TLSを介したHTTP通信のパフォーマンス特性をより詳細に理解し、最適化するための必要性があったと考えられます。既存のベンチマークはTLSを使用しないHTTP通信に焦点を当てていましたが、実際のプロダクション環境ではTLSが広く利用されています。そのため、TLSが有効な状態での net/http
パッケージのパフォーマンスを測定し、潜在的なボトルネックを特定するための専用のベンチマークが求められていました。
特に、並列処理下でのTLSハンドシェイクや暗号化/復号化のオーバーヘッドは、システムの全体的なスループットに大きな影響を与える可能性があります。このベンチマークの追加により、開発者はTLSがパフォーマンスに与える影響を定量的に評価し、将来的な改善のための基礎データを得ることができるようになります。
前提知識の解説
1. Go言語のベンチマーク
Go言語には、標準ライブラリ testing
パッケージにベンチマーク機能が組み込まれています。
go test -bench=.
コマンドで実行されます。Benchmark
というプレフィックスを持つ関数がベンチマーク関数として認識されます。- ベンチマーク関数は
*testing.B
型の引数を受け取ります。 b.N
はベンチマークを実行する回数を示し、ループ内で処理を繰り返します。b.ReportAllocs()
: メモリ割り当ての統計を報告するように設定します。b.ResetTimer()
: タイマーをリセットし、ベンチマーク対象のコードの実行時間のみを測定するようにします。b.SetParallelism(n)
:b.RunParallel
で同時に実行されるゴルーチンの数を設定します。b.RunParallel(func(pb *testing.PB))
:pb.Next()
がtrue
を返す間、並列に処理を実行します。これにより、複数のゴルーチンが同時にベンチマーク対象のコードを実行し、並行処理下でのパフォーマンスを測定できます。
2. net/http
パッケージ
Goの net/http
パッケージは、HTTPクライアントとサーバーの実装を提供します。
httptest.NewServer(handler)
: テスト目的でHTTPサーバーを起動します。ランダムなポートでリッスンし、テスト中にアクセスできるURLを返します。httptest.NewUnstartedServer(handler)
: サーバーを起動せずに作成します。これにより、Start()
またはStartTLS()
を呼び出す前にサーバーの設定を調整できます。ts.Start()
: HTTPサーバーを起動します。ts.StartTLS()
: HTTPSサーバーを起動します。自己署名証明書が自動的に生成され、TLS通信が有効になります。http.Get(url string)
: 指定されたURLにGETリクエストを送信し、レスポンスを返します。http.Client
: HTTPリクエストを送信するためのクライアント構造体です。カスタムのTransport
を設定することで、TLS設定などを細かく制御できます。http.Transport
: HTTPリクエストのラウンドトリップ(接続の確立、リクエストの送信、レスポンスの受信)を実装するインターフェースです。TLS設定はTLSClientConfig
フィールドで指定します。
3. TLS (Transport Layer Security)
TLSは、インターネット上での通信を暗号化し、認証するためのプロトコルです。
- 暗号化: 通信内容を第三者から読み取れないようにします。
- 認証: サーバー(およびオプションでクライアント)が正当であることを確認します。
- データの完全性: データが転送中に改ざんされていないことを保証します。
- TLSハンドシェイク: クライアントとサーバーが安全な通信チャネルを確立するために行う一連のステップです。これには、証明書の交換、鍵の生成、暗号スイートのネゴシエーションなどが含まれます。
crypto/tls
パッケージ: Go言語でTLSを扱うための機能を提供します。tls.Config
: TLS接続の設定を定義する構造体です。InsecureSkipVerify
:true
に設定すると、サーバーの証明書検証をスキップします。これはテスト目的や自己署名証明書を使用する場合に便利ですが、本番環境ではセキュリティリスクがあるため推奨されません。
技術的詳細
このコミットの主要な変更点は、net/http/serve_test.go
ファイル内のベンチマーク関数にTLSサポートを追加したことです。
-
benchmarkClientServerParallel
関数の変更:- 既存の
benchmarkClientServerParallel
関数にuseTLS bool
という新しい引数が追加されました。この引数によって、ベンチマークがTLSを使用するかどうかが制御されます。 - サーバーの起動方法が変更されました。以前は
httptest.NewServer
を直接使用していましたが、変更後はhttptest.NewUnstartedServer
を使用してサーバーを初期化し、useTLS
の値に応じてts.StartTLS()
またはts.Start()
を呼び出すようになりました。これにより、TLSの有無を動的に切り替えられるようになりました。
- 既存の
-
TLSクライアントの設定:
useTLS
がtrue
の場合、クライアントはカスタムのhttp.Transport
を使用するように設定されます。- この
Transport
のTLSClientConfig
フィールドには、InsecureSkipVerify: true
が設定されたtls.Config
が割り当てられます。これは、テスト環境で自己署名証明書を使用する場合に、証明書検証エラーを回避するためのものです。本番環境では、信頼できるCAによって署名された証明書を使用し、この設定をfalse
にするか、デフォルトの検証を使用することが不可欠です。 - クライアントは
http.Client{Transport: noVerifyTransport}
として初期化され、このカスタムクライアントを使用してclient.Get(ts.URL)
が呼び出されるようになります。これにより、TLSが有効なサーバーに対してHTTPリクエストが送信されます。
-
新しいベンチマーク関数の追加:
BenchmarkClientServerParallelTLS4
とBenchmarkClientServerParallelTLS64
という2つの新しいベンチマーク関数が追加されました。- これらの関数は、それぞれ4と64の並列度で
benchmarkClientServerParallel
を呼び出し、useTLS
引数をtrue
に設定します。これにより、TLSが有効な状態で、指定された並列度でのHTTP通信のパフォーマンスが測定されます。
これらの変更により、Goの net/http
パッケージのTLS通信におけるパフォーマンス特性を、並列処理の観点から詳細に分析できるようになりました。特に、TLSハンドシェイクのオーバーヘッド、暗号化/復号化のコスト、およびそれらが多数の同時接続にどのように影響するかを評価するための基盤が提供されます。
コアとなるコードの変更箇所
--- a/src/pkg/net/http/serve_test.go
+++ b/src/pkg/net/http/serve_test.go
@@ -2559,24 +2559,43 @@ func BenchmarkClientServer(b *testing.B) {
}
func BenchmarkClientServerParallel4(b *testing.B) {
- benchmarkClientServerParallel(b, 4)
+ benchmarkClientServerParallel(b, 4, false)
}
func BenchmarkClientServerParallel64(b *testing.B) {
- benchmarkClientServerParallel(b, 64)
+ benchmarkClientServerParallel(b, 64, false)
}
-func benchmarkClientServerParallel(b *testing.B, parallelism int) {
+func BenchmarkClientServerParallelTLS4(b *testing.B) {
+ benchmarkClientServerParallel(b, 4, true)
+}
+
+func BenchmarkClientServerParallelTLS64(b *testing.B) {
+ benchmarkClientServerParallel(b, 64, true)
+}
+
+func benchmarkClientServerParallel(b *testing.B, parallelism int, useTLS bool) {
b.ReportAllocs()
- ts := httptest.NewServer(HandlerFunc(func(rw ResponseWriter, r *Request) {
+ ts := httptest.NewUnstartedServer(HandlerFunc(func(rw ResponseWriter, r *Request) {
fmt.Fprintf(rw, "Hello world.\n")
}))
+ if useTLS {
+ ts.StartTLS()
+ } else {
+ ts.Start()
+ }
defer ts.Close()
b.ResetTimer()
b.SetParallelism(parallelism)
b.RunParallel(func(pb *testing.PB) {
+ noVerifyTransport := &Transport{
+ TLSClientConfig: &tls.Config{
+ InsecureSkipVerify: true,
+ },
+ }
+ client := &Client{Transport: noVerifyTransport}
for pb.Next() {
- res, err := Get(ts.URL)
+ res, err := client.Get(ts.URL)
if err != nil {
b.Logf("Get: %v", err)
continue
コアとなるコードの解説
1. benchmarkClientServerParallel
関数のシグネチャ変更
func benchmarkClientServerParallel(b *testing.B, parallelism int, useTLS bool) {
この行は、既存のベンチマークヘルパー関数 benchmarkClientServerParallel
に useTLS bool
という新しいパラメータを追加しています。これにより、この関数がTLSを使用するかどうかを呼び出し元から制御できるようになります。
2. サーバーの起動方法の変更
ts := httptest.NewUnstartedServer(HandlerFunc(func(rw ResponseWriter, r *Request) {
fmt.Fprintf(rw, "Hello world.\n")
}))
if useTLS {
ts.StartTLS()
} else {
ts.Start()
}
以前は httptest.NewServer
を直接呼び出していましたが、ここではまず httptest.NewUnstartedServer
を使用して、まだ起動していないサーバーインスタンスを作成しています。
その後の if useTLS
ブロックで、useTLS
が true
の場合は ts.StartTLS()
を呼び出してHTTPSサーバーとして起動し、false
の場合は ts.Start()
を呼び出して通常のHTTPサーバーとして起動します。これにより、単一のヘルパー関数でTLSの有無を切り替える柔軟性が得られます。
3. TLSクライアントの設定(b.RunParallel
内)
noVerifyTransport := &Transport{
TLSClientConfig: &tls.Config{
InsecureSkipVerify: true,
},
}
client := &Client{Transport: noVerifyTransport}
b.RunParallel
の内部、つまり各並列ゴルーチン内で、TLSを使用する場合のクライアント設定が行われています。
noVerifyTransport
というhttp.Transport
のインスタンスが作成されます。- このトランスポートの
TLSClientConfig
フィールドにtls.Config
が設定され、その中のInsecureSkipVerify
がtrue
に設定されています。これは、テスト用の自己署名証明書を使用する際に、証明書検証エラーを回避するためのものです。 - このカスタムトランスポートを持つ
http.Client
インスタンスが作成されます。
4. リクエストの送信方法の変更
for pb.Next() {
res, err := client.Get(ts.URL)
以前は http.Get(ts.URL)
を直接呼び出していましたが、TLSが有効な場合は、上記で作成したカスタムクライアント client
を使用して client.Get(ts.URL)
を呼び出すように変更されています。これにより、TLS設定が適用されたHTTPリクエストが送信されます。
5. 新しいベンチマーク関数の追加
func BenchmarkClientServerParallelTLS4(b *testing.B) {
benchmarkClientServerParallel(b, 4, true)
}
func BenchmarkClientServerParallelTLS64(b *testing.B) {
benchmarkClientServerParallel(b, 64, true)
}
これらの新しい関数は、それぞれ4と64の並列度で benchmarkClientServerParallel
を呼び出し、useTLS
引数を true
に設定しています。これにより、TLSが有効な状態での並列ベンチマークが実行可能になります。既存の BenchmarkClientServerParallel4
と BenchmarkClientServerParallel64
も、useTLS
を false
に設定するように変更されています。
これらの変更により、Goの net/http
パッケージのTLS通信におけるパフォーマンス特性を、並列処理の観点から詳細に分析できるようになりました。特に、TLSハンドシェイクのオーバーヘッド、暗号化/復号化のコスト、およびそれらが多数の同時接続にどのように影響するかを評価するための基盤が提供されます。
関連リンク
- Go言語の
net/http
パッケージのドキュメント: https://pkg.go.dev/net/http - Go言語の
testing
パッケージのドキュメント: https://pkg.go.dev/testing - Go言語の
crypto/tls
パッケージのドキュメント: https://pkg.go.dev/crypto/tls - Go言語のベンチマークに関する公式ブログ記事 (Go 1.2 Benchmarking): https://go.dev/blog/go1.2-benchmarking
参考にした情報源リンク
- 上記のGo言語公式ドキュメント
- TLS (Transport Layer Security) の一般的な知識
- HTTPプロトコルの一般的な知識
- Go言語のベンチマークの書き方に関する一般的な情報
- コミットメッセージと変更されたコードの内容
- Go CL 110080045: https://go.dev/cl/110080045 (これは元コミット内容に記載されているリンクであり、変更の詳細を確認するために参照しました。)
- GitHubのgolang/goリポジトリ: https://github.com/golang/go
- Go言語のテストとベンチマークに関する一般的なチュートリアルや記事