FastHTTP
Go向けの高性能HTTPパッケージ。net/httpの最大10倍の性能を実現する設計。ゼロメモリアロケーション、高度な最適化により極限の性能を追求。大量のリクエスト処理やレイテンシが重要なアプリケーションに特化。
GitHub概要
valyala/fasthttp
Fast HTTP package for Go. Tuned for high performance. Zero memory allocations in hot paths. Up to 10x faster than net/http
トピックス
スター履歴
ライブラリ
fasthttp
概要
fasthttpは「Go言語向けの高速HTTPクライアント・サーバーライブラリ」として開発された、標準のnet/httpより最大10倍高速なHTTP通信ライブラリです。「ゼロアロケーション設計」をコンセプトに、メモリ割り当てを極限まで削減し、オブジェクトプールとコネクションプールを活用した最適化により、高負荷環境下での圧倒的なパフォーマンスを実現。企業レベルの大規模Webサービスで1.5M以上の同時接続から毎秒200K以上のリクエストを処理する実績を持ち、Go言語でのHTTP通信における究極のパフォーマンスソリューションとして地位を確立しています。
詳細
fasthttp 2025年版は高負荷HTTP通信における決定版として、標準のnet/httpを大幅に上回る性能を提供し続けています。ゼロアロケーション設計による徹底したメモリ最適化、オブジェクトプールによるGC負荷軽減、効率的なコネクション管理により、レイテンシとスループットの両面で劇的な改善を実現。VertaMediaなどの大手企業で毎秒数十万リクエストの処理実績があり、マイクロサービス、API Gateway、高負荷Webサーバーで威力を発揮します。net/httpとは異なるAPIを採用しているため移行には注意が必要ですが、パフォーマンス重視の場面では圧倒的な優位性を提供します。
主な特徴
- ゼロアロケーション設計: メモリ割り当てを極限まで削減した最適化
- オブジェクトプールとコネクションプール: 効率的なリソース再利用システム
- 超高速処理: net/httpの最大10倍のパフォーマンス実現
- 大規模対応: 数十万RPS・数百万同時接続の処理能力
- 柔軟なAPI: レスポンス送信前の任意タイミングでのヘッダー・ボディ設定
- 包括的な機能: HTTPクライアント・サーバー両方の完全実装
メリット・デメリット
メリット
- net/httpを大幅に上回る圧倒的なパフォーマンス(最大10倍高速)
- ゼロアロケーション設計によるメモリ効率とGC負荷軽減
- 大規模サービスでの実証済み安定性と処理能力
- オブジェクト・コネクションプールによる効率的なリソース管理
- 高度なカスタマイズ性とパフォーマンスチューニング機能
- HTTPクライアント・サーバー両方の包括的機能提供
デメリット
- net/httpとAPI互換性がなく移行時にコード変更が必要
- ストリーミング処理がnet/httpより限定的
- HTTP/2サポートが開発中でまだ完全ではない
- エコシステムと学習リソースがnet/httpより少ない
- 適切な最適化なしでは性能向上が期待できない場合がある
- Go 1.23以降の比較的新しいバージョンが必要
参考ページ
書き方の例
インストールと基本セットアップ
# fasthttpのインストール
go get -u github.com/valyala/fasthttp
# Go環境での確認
go version # Go 1.23以降が必要
# 基本的なプロジェクト初期化
go mod init fasthttp-example
go get github.com/valyala/fasthttp
基本的なHTTPサーバー実装
package main
import (
"fmt"
"log"
"github.com/valyala/fasthttp"
)
// 基本的なリクエストハンドラー
func requestHandler(ctx *fasthttp.RequestCtx) {
// リクエスト情報の取得
fmt.Fprintf(ctx, "Hello, World! リクエストパス: %q\n", ctx.Path())
fmt.Fprintf(ctx, "リクエストメソッド: %q\n", ctx.Method())
fmt.Fprintf(ctx, "ユーザーエージェント: %q\n", ctx.UserAgent())
// レスポンスヘッダーの設定
ctx.SetContentType("text/plain; charset=utf-8")
ctx.SetStatusCode(fasthttp.StatusOK)
}
// 高度なリクエストハンドラー
func advancedHandler(ctx *fasthttp.RequestCtx) {
// パスベースのルーティング
switch string(ctx.Path()) {
case "/":
ctx.SetContentType("text/html")
fmt.Fprintf(ctx, "<h1>ホームページ</h1><p>fasthttp Server</p>")
case "/api/status":
ctx.SetContentType("application/json")
fmt.Fprintf(ctx, `{"status": "ok", "server": "fasthttp"}`)
case "/api/headers":
ctx.SetContentType("application/json")
fmt.Fprintf(ctx, `{"headers": {`)
ctx.Request.Header.VisitAll(func(key, value []byte) {
fmt.Fprintf(ctx, `"%s": "%s",`, string(key), string(value))
})
fmt.Fprintf(ctx, `}}`)
default:
ctx.Error("見つかりません", fasthttp.StatusNotFound)
}
}
// 構造体ベースのハンドラー
type MyHandler struct {
name string
}
func (h *MyHandler) HandleFastHTTP(ctx *fasthttp.RequestCtx) {
fmt.Fprintf(ctx, "Handler名: %s\n", h.name)
fmt.Fprintf(ctx, "リクエストURI: %q", ctx.RequestURI())
}
func main() {
// 基本サーバー起動
log.Println("fasthttpサーバーを :8080 で起動中...")
log.Fatal(fasthttp.ListenAndServe(":8080", requestHandler))
// 高度なサーバー設定
server := &fasthttp.Server{
Handler: advancedHandler,
ReadTimeout: time.Second * 30,
WriteTimeout: time.Second * 30,
IdleTimeout: time.Second * 60,
MaxConnsPerIP: 1000,
MaxRequestsPerConn: 1000,
MaxRequestBodySize: 1024 * 1024, // 1MB
}
log.Println("カスタムサーバーを :8081 で起動中...")
log.Fatal(server.ListenAndServe(":8081"))
// 構造体ハンドラーの使用
myHandler := &MyHandler{name: "カスタムハンドラー"}
log.Fatal(fasthttp.ListenAndServe(":8082", myHandler.HandleFastHTTP))
}
HTTPクライアント実装(GET/POST/PUT/DELETE)
package main
import (
"fmt"
"log"
"time"
"github.com/valyala/fasthttp"
)
func main() {
// 基本的なGETリクエスト
statusCode, body, err := fasthttp.Get(nil, "https://httpbin.org/get")
if err != nil {
log.Fatalf("GETリクエストエラー: %v", err)
}
fmt.Printf("ステータス: %d\nレスポンス: %s\n", statusCode, body)
// クエリパラメータ付きGETリクエスト
req := fasthttp.AcquireRequest()
resp := fasthttp.AcquireResponse()
defer fasthttp.ReleaseRequest(req)
defer fasthttp.ReleaseResponse(resp)
req.SetRequestURI("https://httpbin.org/get?page=1&limit=10")
req.Header.SetMethod(fasthttp.MethodGet)
req.Header.Set("User-Agent", "fasthttp-client/1.0")
client := &fasthttp.Client{
ReadTimeout: time.Second * 30,
WriteTimeout: time.Second * 30,
}
err = client.Do(req, resp)
if err != nil {
log.Fatalf("リクエストエラー: %v", err)
}
fmt.Printf("ステータス: %d\n", resp.StatusCode())
fmt.Printf("レスポンス: %s\n", resp.Body())
// POSTリクエスト(JSON送信)
req.Reset()
resp.Reset()
jsonData := `{"name": "田中太郎", "email": "[email protected]", "age": 30}`
req.SetRequestURI("https://httpbin.org/post")
req.Header.SetMethod(fasthttp.MethodPost)
req.Header.SetContentType("application/json")
req.Header.Set("Authorization", "Bearer your-token")
req.SetBody([]byte(jsonData))
err = client.Do(req, resp)
if err != nil {
log.Fatalf("POSTリクエストエラー: %v", err)
}
fmt.Printf("POST ステータス: %d\n", resp.StatusCode())
fmt.Printf("POST レスポンス: %s\n", resp.Body())
// PUTリクエスト(データ更新)
req.Reset()
resp.Reset()
updateData := `{"name": "田中次郎", "email": "[email protected]"}`
req.SetRequestURI("https://httpbin.org/put")
req.Header.SetMethod(fasthttp.MethodPut)
req.Header.SetContentType("application/json")
req.SetBody([]byte(updateData))
err = client.Do(req, resp)
if err != nil {
log.Fatalf("PUTリクエストエラー: %v", err)
}
fmt.Printf("PUT ステータス: %d\n", resp.StatusCode())
// DELETEリクエスト
req.Reset()
resp.Reset()
req.SetRequestURI("https://httpbin.org/delete")
req.Header.SetMethod(fasthttp.MethodDelete)
req.Header.Set("Authorization", "Bearer your-token")
err = client.Do(req, resp)
if err != nil {
log.Fatalf("DELETEリクエストエラー: %v", err)
}
fmt.Printf("DELETE ステータス: %d\n", resp.StatusCode())
// HostClientを使用した効率的なリクエスト
hostClient := &fasthttp.HostClient{
Addr: "httpbin.org:443",
IsTLS: true,
MaxConns: 100,
ReadTimeout: time.Second * 30,
WriteTimeout: time.Second * 30,
}
req.Reset()
resp.Reset()
req.SetRequestURI("https://httpbin.org/get")
req.Header.SetMethod(fasthttp.MethodGet)
err = hostClient.Do(req, resp)
if err != nil {
log.Fatalf("HostClientリクエストエラー: %v", err)
}
fmt.Printf("HostClient ステータス: %d\n", resp.StatusCode())
}
高度な設定とカスタマイズ(認証、タイムアウト、プロキシ等)
package main
import (
"crypto/tls"
"fmt"
"log"
"time"
"github.com/valyala/fasthttp"
)
func main() {
// カスタムクライアント設定
client := &fasthttp.Client{
// タイムアウト設定
ReadTimeout: time.Second * 30,
WriteTimeout: time.Second * 30,
MaxIdleConnDuration: time.Minute * 5,
// コネクション制限
MaxConnsPerHost: 100,
MaxIdleConnDuration: time.Minute,
// TLS設定
TLSConfig: &tls.Config{
InsecureSkipVerify: false, // 本番では true にしない
},
// リトライ設定
MaxIdemponentCallAttempts: 3,
}
req := fasthttp.AcquireRequest()
resp := fasthttp.AcquireResponse()
defer fasthttp.ReleaseRequest(req)
defer fasthttp.ReleaseResponse(resp)
// カスタムヘッダー設定
req.SetRequestURI("https://httpbin.org/headers")
req.Header.SetMethod(fasthttp.MethodGet)
req.Header.Set("User-Agent", "fasthttp-client/1.0")
req.Header.Set("Accept", "application/json")
req.Header.Set("Accept-Language", "ja-JP,en-US")
req.Header.Set("X-API-Version", "v2")
req.Header.Set("X-Request-ID", "req-12345")
// Basic認証
req.Header.Set("Authorization", "Basic dXNlcjpwYXNz") // user:pass
err := client.Do(req, resp)
if err != nil {
log.Fatalf("認証リクエストエラー: %v", err)
}
fmt.Printf("認証レスポンス: %s\n", resp.Body())
// プロキシ設定付きクライアント
proxyClient := &fasthttp.Client{
Dial: fasthttp.DialDualStackTimeout(time.Second * 30),
// プロキシはfasthttpでは直接サポートされていないため、
// カスタムDialer実装またはサードパーティライブラリが必要
}
// Cookie設定
req.Reset()
resp.Reset()
req.SetRequestURI("https://httpbin.org/cookies")
req.Header.SetMethod(fasthttp.MethodGet)
req.Header.SetCookie("session_id", "abc123")
req.Header.SetCookie("user_pref", "dark_mode")
err = client.Do(req, resp)
if err != nil {
log.Fatalf("Cookieリクエストエラー: %v", err)
}
fmt.Printf("Cookie レスポンス: %s\n", resp.Body())
// マルチパートフォームデータ送信
req.Reset()
resp.Reset()
req.SetRequestURI("https://httpbin.org/post")
req.Header.SetMethod(fasthttp.MethodPost)
req.Header.SetContentType("multipart/form-data; boundary=----formdata")
multipartBody := `------formdata
Content-Disposition: form-data; name="username"
testuser
------formdata
Content-Disposition: form-data; name="password"
secret123
------formdata--`
req.SetBody([]byte(multipartBody))
err = client.Do(req, resp)
if err != nil {
log.Fatalf("マルチパートリクエストエラー: %v", err)
}
fmt.Printf("マルチパート ステータス: %d\n", resp.StatusCode())
// ストリーミング対応の大きなファイル処理
req.Reset()
resp.Reset()
req.SetRequestURI("https://httpbin.org/stream/100")
req.Header.SetMethod(fasthttp.MethodGet)
err = client.Do(req, resp)
if err != nil {
log.Fatalf("ストリーミングリクエストエラー: %v", err)
}
// レスポンスの段階的処理
bodyBytes := resp.Body()
fmt.Printf("ストリーミングデータサイズ: %d bytes\n", len(bodyBytes))
// カスタムHostClient(特定ホスト専用)
hostClient := &fasthttp.HostClient{
Addr: "httpbin.org:443",
IsTLS: true,
MaxConns: 50,
ReadTimeout: time.Second * 15,
WriteTimeout: time.Second * 15,
// Keep-Alive設定
MaxIdleConnDuration: time.Minute * 5,
// カスタムTLS設定
TLSConfig: &tls.Config{
ServerName: "httpbin.org",
MinVersion: tls.VersionTLS12,
},
}
req.Reset()
resp.Reset()
req.SetRequestURI("https://httpbin.org/get")
req.Header.SetMethod(fasthttp.MethodGet)
err = hostClient.Do(req, resp)
if err != nil {
log.Fatalf("HostClientエラー: %v", err)
}
fmt.Printf("HostClient ステータス: %d\n", resp.StatusCode())
}
エラーハンドリングとリトライ機能
package main
import (
"fmt"
"log"
"time"
"github.com/valyala/fasthttp"
)
// カスタムエラータイプ
type HTTPError struct {
StatusCode int
Message string
URL string
}
func (e *HTTPError) Error() string {
return fmt.Sprintf("HTTP %d: %s (URL: %s)", e.StatusCode, e.Message, e.URL)
}
// 安全なリクエスト実行関数
func safeRequest(client *fasthttp.Client, req *fasthttp.Request, resp *fasthttp.Response) error {
err := client.Do(req, resp)
if err != nil {
return fmt.Errorf("リクエスト実行エラー: %w", err)
}
// ステータスコードチェック
statusCode := resp.StatusCode()
if statusCode >= 400 {
return &HTTPError{
StatusCode: statusCode,
Message: string(resp.Body()),
URL: string(req.RequestURI()),
}
}
return nil
}
// リトライ付きリクエスト実行
func requestWithRetry(client *fasthttp.Client, req *fasthttp.Request, maxRetries int, backoffFactor time.Duration) (*fasthttp.Response, error) {
resp := fasthttp.AcquireResponse()
for attempt := 0; attempt <= maxRetries; attempt++ {
resp.Reset()
err := safeRequest(client, req, resp)
if err == nil {
return resp, nil
}
// リトライ可能なエラーかチェック
if httpErr, ok := err.(*HTTPError); ok {
// 4xxエラーはリトライしない
if httpErr.StatusCode >= 400 && httpErr.StatusCode < 500 {
fasthttp.ReleaseResponse(resp)
return nil, err
}
}
if attempt == maxRetries {
fasthttp.ReleaseResponse(resp)
return nil, fmt.Errorf("最大試行回数に達しました: %w", err)
}
// バックオフ待機
waitTime := backoffFactor * time.Duration(1<<attempt)
log.Printf("試行 %d 失敗, %v 後に再試行: %v", attempt+1, waitTime, err)
time.Sleep(waitTime)
}
fasthttp.ReleaseResponse(resp)
return nil, fmt.Errorf("予期しないエラー")
}
// レート制限対応クライアント
type RateLimitedClient struct {
client *fasthttp.Client
limiter chan struct{}
retryDelay time.Duration
}
func NewRateLimitedClient(requestsPerSecond int, retryDelay time.Duration) *RateLimitedClient {
return &RateLimitedClient{
client: &fasthttp.Client{
ReadTimeout: time.Second * 30,
WriteTimeout: time.Second * 30,
},
limiter: make(chan struct{}, requestsPerSecond),
retryDelay: retryDelay,
}
}
func (rlc *RateLimitedClient) Do(req *fasthttp.Request, resp *fasthttp.Response) error {
// レート制限
select {
case rlc.limiter <- struct{}{}:
defer func() { <-rlc.limiter }()
default:
time.Sleep(rlc.retryDelay)
return rlc.Do(req, resp)
}
return rlc.client.Do(req, resp)
}
func main() {
client := &fasthttp.Client{
ReadTimeout: time.Second * 30,
WriteTimeout: time.Second * 30,
MaxIdemponentCallAttempts: 1, // fasthttpの自動リトライを無効化
}
req := fasthttp.AcquireRequest()
defer fasthttp.ReleaseRequest(req)
// 正常なリクエストテスト
req.SetRequestURI("https://httpbin.org/get")
req.Header.SetMethod(fasthttp.MethodGet)
resp, err := requestWithRetry(client, req, 3, time.Second)
if err != nil {
log.Printf("リクエスト失敗: %v", err)
} else {
fmt.Printf("成功: ステータス %d\n", resp.StatusCode())
fasthttp.ReleaseResponse(resp)
}
// エラーレスポンステスト
req.Reset()
req.SetRequestURI("https://httpbin.org/status/404")
req.Header.SetMethod(fasthttp.MethodGet)
resp, err = requestWithRetry(client, req, 3, time.Second)
if err != nil {
if httpErr, ok := err.(*HTTPError); ok {
fmt.Printf("HTTPエラー: %d - %s\n", httpErr.StatusCode, httpErr.Message)
} else {
log.Printf("その他のエラー: %v", err)
}
}
if resp != nil {
fasthttp.ReleaseResponse(resp)
}
// タイムアウトテスト
timeoutClient := &fasthttp.Client{
ReadTimeout: time.Millisecond * 100, // 短いタイムアウト
WriteTimeout: time.Millisecond * 100,
}
req.Reset()
req.SetRequestURI("https://httpbin.org/delay/1")
req.Header.SetMethod(fasthttp.MethodGet)
resp, err = requestWithRetry(timeoutClient, req, 2, time.Millisecond*500)
if err != nil {
log.Printf("タイムアウトエラー(期待される): %v", err)
}
if resp != nil {
fasthttp.ReleaseResponse(resp)
}
// レート制限付きクライアントのテスト
rateLimitedClient := NewRateLimitedClient(5, time.Millisecond*200)
for i := 0; i < 10; i++ {
req.Reset()
resp := fasthttp.AcquireResponse()
req.SetRequestURI(fmt.Sprintf("https://httpbin.org/get?request=%d", i))
req.Header.SetMethod(fasthttp.MethodGet)
start := time.Now()
err := rateLimitedClient.Do(req, resp)
duration := time.Since(start)
if err != nil {
log.Printf("リクエスト %d エラー: %v", i, err)
} else {
fmt.Printf("リクエスト %d 完了: ステータス %d, 所要時間: %v\n",
i, resp.StatusCode(), duration)
}
fasthttp.ReleaseResponse(resp)
}
// 並行エラーハンドリング例
const numRequests = 5
results := make(chan string, numRequests)
for i := 0; i < numRequests; i++ {
go func(id int) {
req := fasthttp.AcquireRequest()
defer fasthttp.ReleaseRequest(req)
// 50%の確率で404エラーを発生させる
url := "https://httpbin.org/get"
if id%2 == 0 {
url = "https://httpbin.org/status/404"
}
req.SetRequestURI(url)
req.Header.SetMethod(fasthttp.MethodGet)
resp, err := requestWithRetry(client, req, 2, time.Millisecond*500)
if err != nil {
results <- fmt.Sprintf("ゴルーチン %d: エラー - %v", id, err)
} else {
results <- fmt.Sprintf("ゴルーチン %d: 成功 - ステータス %d", id, resp.StatusCode())
fasthttp.ReleaseResponse(resp)
}
}(i)
}
// 結果収集
for i := 0; i < numRequests; i++ {
result := <-results
fmt.Println(result)
}
}
パフォーマンス最適化とベンチマーク
package main
import (
"fmt"
"log"
"runtime"
"sync"
"time"
"github.com/valyala/fasthttp"
)
// パフォーマンス監視用の構造体
type PerformanceMonitor struct {
requestCount int64
errorCount int64
totalDuration time.Duration
mu sync.RWMutex
startTime time.Time
}
func NewPerformanceMonitor() *PerformanceMonitor {
return &PerformanceMonitor{
startTime: time.Now(),
}
}
func (pm *PerformanceMonitor) RecordRequest(duration time.Duration, hasError bool) {
pm.mu.Lock()
defer pm.mu.Unlock()
pm.requestCount++
pm.totalDuration += duration
if hasError {
pm.errorCount++
}
}
func (pm *PerformanceMonitor) GetStats() (int64, int64, time.Duration, float64) {
pm.mu.RLock()
defer pm.mu.RUnlock()
elapsed := time.Since(pm.startTime)
rps := float64(pm.requestCount) / elapsed.Seconds()
return pm.requestCount, pm.errorCount, pm.totalDuration, rps
}
// 最適化されたクライアント設定
func createOptimizedClient() *fasthttp.Client {
return &fasthttp.Client{
// 効率的なタイムアウト設定
ReadTimeout: time.Second * 10,
WriteTimeout: time.Second * 10,
// コネクション最適化
MaxConnsPerHost: 100,
MaxIdleConnDuration: time.Minute * 5,
MaxConnDuration: time.Hour,
MaxIdemponentCallAttempts: 3,
// TCPパフォーマンス最適化
ReadBufferSize: 64 * 1024, // 64KB
WriteBufferSize: 64 * 1024, // 64KB
// Keep-Alive設定
MaxConnWaitTimeout: time.Second * 5,
}
}
// バッチリクエスト処理
func batchRequests(client *fasthttp.Client, urls []string, concurrency int) {
monitor := NewPerformanceMonitor()
semaphore := make(chan struct{}, concurrency)
var wg sync.WaitGroup
fmt.Printf("バッチ処理開始: %d URL, 並行数: %d\n", len(urls), concurrency)
for i, url := range urls {
wg.Add(1)
go func(id int, targetURL string) {
defer wg.Done()
// セマフォで並行数制御
semaphore <- struct{}{}
defer func() { <-semaphore }()
req := fasthttp.AcquireRequest()
resp := fasthttp.AcquireResponse()
defer fasthttp.ReleaseRequest(req)
defer fasthttp.ReleaseResponse(resp)
req.SetRequestURI(targetURL)
req.Header.SetMethod(fasthttp.MethodGet)
start := time.Now()
err := client.Do(req, resp)
duration := time.Since(start)
hasError := err != nil || resp.StatusCode() >= 400
monitor.RecordRequest(duration, hasError)
if id%100 == 0 {
fmt.Printf("進捗: %d/%d 完了\n", id, len(urls))
}
}(i, url)
}
wg.Wait()
// 統計表示
requests, errors, totalDuration, rps := monitor.GetStats()
avgDuration := totalDuration / time.Duration(requests)
fmt.Printf("\n=== バッチ処理結果 ===\n")
fmt.Printf("総リクエスト数: %d\n", requests)
fmt.Printf("エラー数: %d (%.2f%%)\n", errors, float64(errors)/float64(requests)*100)
fmt.Printf("平均レスポンス時間: %v\n", avgDuration)
fmt.Printf("RPS (Requests Per Second): %.2f\n", rps)
}
// コネクションプール監視
func monitorConnectionPool(client *fasthttp.Client) {
ticker := time.NewTicker(time.Second * 5)
defer ticker.Stop()
for {
select {
case <-ticker.C:
// ここでは簡易的なメモリ使用量を表示
var m runtime.MemStats
runtime.ReadMemStats(&m)
fmt.Printf("メモリ使用量: Alloc = %.2f MB, Sys = %.2f MB, NumGC = %d\n",
float64(m.Alloc)/1024/1024,
float64(m.Sys)/1024/1024,
m.NumGC)
}
}
}
// 負荷テスト関数
func loadTest(targetURL string, duration time.Duration, concurrency int) {
client := createOptimizedClient()
monitor := NewPerformanceMonitor()
fmt.Printf("負荷テスト開始: %s, 時間: %v, 並行数: %d\n", targetURL, duration, concurrency)
// メモリ監視を別ゴルーチンで開始
go monitorConnectionPool(client)
semaphore := make(chan struct{}, concurrency)
endTime := time.Now().Add(duration)
var wg sync.WaitGroup
for time.Now().Before(endTime) {
wg.Add(1)
go func() {
defer wg.Done()
semaphore <- struct{}{}
defer func() { <-semaphore }()
req := fasthttp.AcquireRequest()
resp := fasthttp.AcquireResponse()
defer fasthttp.ReleaseRequest(req)
defer fasthttp.ReleaseResponse(resp)
req.SetRequestURI(targetURL)
req.Header.SetMethod(fasthttp.MethodGet)
start := time.Now()
err := client.Do(req, resp)
requestDuration := time.Since(start)
hasError := err != nil || resp.StatusCode() >= 400
monitor.RecordRequest(requestDuration, hasError)
}()
}
wg.Wait()
// 最終統計
requests, errors, totalDuration, rps := monitor.GetStats()
avgDuration := totalDuration / time.Duration(requests)
fmt.Printf("\n=== 負荷テスト結果 ===\n")
fmt.Printf("総リクエスト数: %d\n", requests)
fmt.Printf("エラー数: %d (%.2f%%)\n", errors, float64(errors)/float64(requests)*100)
fmt.Printf("平均レスポンス時間: %v\n", avgDuration)
fmt.Printf("最大RPS: %.2f\n", rps)
fmt.Printf("スループット: %.2f MB/s (推定)\n", rps*1024/1024) // 1KB/requestと仮定
}
func main() {
// 基本的なパフォーマンステスト
urls := make([]string, 1000)
for i := range urls {
urls[i] = fmt.Sprintf("https://httpbin.org/get?id=%d", i)
}
client := createOptimizedClient()
// バッチリクエストテスト
batchRequests(client, urls[:100], 20)
// 負荷テスト(実際の本番環境では適切なテストサーバーを使用)
// loadTest("https://httpbin.org/get", time.Minute, 50)
// ベンチマーク比較(fasthttp vs net/http)
fmt.Println("\n=== fasthttpベンチマーク例 ===")
fmt.Println("実際のベンチマーク結果:")
fmt.Println("fasthttp: 865 ns/op, 0 allocs/op")
fmt.Println("net/http: 12567 ns/op, 35 allocs/op")
fmt.Println("性能向上: ~14.5倍高速, ゼロアロケーション")
// メモリ効率性デモ
demonstrateMemoryEfficiency()
}
func demonstrateMemoryEfficiency() {
fmt.Println("\n=== メモリ効率性デモ ===")
// オブジェクトプールの活用
req := fasthttp.AcquireRequest()
resp := fasthttp.AcquireResponse()
// 使用後は必ずプールに戻す
defer fasthttp.ReleaseRequest(req)
defer fasthttp.ReleaseResponse(resp)
// ゼロアロケーションの文字列操作例
uri := make([]byte, 0, 100)
uri = append(uri, "https://example.com/api"...)
uri = append(uri, "?param=value"...)
req.SetRequestURIBytes(uri)
fmt.Println("オブジェクトプールとゼロアロケーション操作を実装")
fmt.Printf("URI設定完了: %s\n", req.RequestURI())
}