Files
v-hono/tests/test_high_concurrency.go
meiseayoung 9eb360926b feat(usockets): optimize high concurrency support up to 10,000+ connections
- Increase uSockets listen() backlog from 512 to 16384 in bsd.c
- Add high concurrency test suite (5000-10000 concurrent connections)
- Add HIGH_CONCURRENCY.md documentation with optimization guide
- Add usockets/build.sh script for rebuilding uSockets library
- Update README with latest benchmark results

Performance (macOS M3 Max):
- 5,000 concurrent: 81,524 RPS, 100% success
- 10,000 concurrent: 24,198 RPS, 100% success

System requirements:
- kern.ipc.somaxconn >= 8192
- ulimit -n 65535
2026-01-03 20:45:30 +08:00

246 lines
7.4 KiB
Go

// 高并发测试 (5000-10000 并发)
//
// 使用方法:
// 1. 启动服务器 (必须设置 ulimit): ulimit -n 65535 && ./bench_server_usockets
// 2. 运行测试: ulimit -n 65535 && go run v-hono/tests/test_high_concurrency.go
// 3. 单独测试某个级别: ulimit -n 65535 && go run v-hono/tests/test_high_concurrency.go 8000
//
// 重要提示:
// - 服务器和客户端都需要设置 ulimit -n 65535
// - 连续测试多个并发级别时,建议每次测试前重启服务器
// - TIME_WAIT 连接会影响后续测试,建议等待 10 秒后再测试下一个级别
//
// 系统配置要求 (macOS):
// sudo sysctl -w kern.ipc.somaxconn=8192
// ulimit -n 65535
package main
import (
"fmt"
"io"
"net/http"
"os"
"sort"
"strconv"
"sync"
"sync/atomic"
"time"
)
type BenchResult struct {
Concurrency int
TotalReqs int64
SuccessReqs int64
RPS float64
AvgLatency float64
P99Latency float64
SuccessRate float64
}
func main() {
baseURL := "http://127.0.0.1:8080/"
duration := 10 * time.Second
// 默认测试级别: 5000, 6000, 7000, 8000, 9000, 10000
concurrencyLevels := []int{5000, 6000, 7000, 8000, 9000, 10000}
// 支持命令行参数指定单个并发级别
if len(os.Args) > 1 {
level, err := strconv.Atoi(os.Args[1])
if err == nil {
concurrencyLevels = []int{level}
}
}
fmt.Println("╔═══════════════════════════════════════════════════════════════════════════╗")
fmt.Println("║ v-hono 高并发测试 (5000-10000 并发) ║")
fmt.Println("╚═══════════════════════════════════════════════════════════════════════════╝")
fmt.Println()
// 检查服务器是否运行
if !checkServer(baseURL) {
fmt.Println("❌ 服务器未运行")
fmt.Println(" 请先启动: ./bench_server_usockets")
fmt.Println()
fmt.Println(" 系统配置要求:")
fmt.Println(" - macOS: sudo sysctl -w kern.ipc.somaxconn=8192")
fmt.Println(" - ulimit -n 65535")
return
}
fmt.Println("✅ 服务器已就绪")
fmt.Println()
results := make([]BenchResult, 0, len(concurrencyLevels))
for _, conns := range concurrencyLevels {
result := runBenchmark(baseURL, conns, duration)
results = append(results, result)
// 测试间隔,让系统恢复 (TIME_WAIT 连接需要时间释放)
// macOS TIME_WAIT 默认 15-30 秒,建议等待 60 秒
if len(concurrencyLevels) > 1 {
fmt.Println(" ⏳ 等待 60 秒让系统恢复 (TIME_WAIT 连接释放)...")
time.Sleep(60 * time.Second)
}
}
// 输出汇总报告
printSummary(results)
}
func checkServer(baseURL string) bool {
client := &http.Client{Timeout: 2 * time.Second}
for i := 0; i < 5; i++ {
resp, err := client.Get(baseURL)
if err == nil && resp.StatusCode < 400 {
resp.Body.Close()
return true
}
time.Sleep(200 * time.Millisecond)
}
return false
}
func runBenchmark(baseURL string, conns int, duration time.Duration) BenchResult {
fmt.Printf("🔥 测试 %d 并发连接 (持续 %v)\n", conns, duration)
var total, success int64
var totalLatencyNs int64
latencies := make([]int64, 0, 1000000)
var mu sync.Mutex
client := &http.Client{
Timeout: 60 * time.Second,
Transport: &http.Transport{
MaxIdleConns: conns * 2,
MaxIdleConnsPerHost: conns * 2,
MaxConnsPerHost: 0,
IdleConnTimeout: 120 * time.Second,
DisableKeepAlives: false,
ForceAttemptHTTP2: false,
},
}
var wg sync.WaitGroup
stop := make(chan struct{})
start := time.Now()
// 同时启动所有连接
for i := 0; i < conns; i++ {
wg.Add(1)
go func() {
defer wg.Done()
for {
select {
case <-stop:
return
default:
t0 := time.Now()
resp, err := client.Get(baseURL)
lat := time.Since(t0).Nanoseconds()
atomic.AddInt64(&total, 1)
atomic.AddInt64(&totalLatencyNs, lat)
mu.Lock()
latencies = append(latencies, lat)
mu.Unlock()
if err != nil {
continue
}
io.Copy(io.Discard, resp.Body)
resp.Body.Close()
if resp.StatusCode < 400 {
atomic.AddInt64(&success, 1)
}
}
}
}()
}
time.Sleep(duration)
close(stop)
wg.Wait()
elapsed := time.Since(start)
// 计算 P99
sort.Slice(latencies, func(i, j int) bool { return latencies[i] < latencies[j] })
p99 := int64(0)
if len(latencies) > 0 {
idx := len(latencies) * 99 / 100
p99 = latencies[idx]
}
avgLat := float64(totalLatencyNs) / float64(total) / 1e6
rps := float64(total) / elapsed.Seconds()
successRate := float64(success) / float64(total) * 100
// 判断测试结果
status := "✅"
if successRate < 99.0 {
status = "⚠️"
}
if successRate < 90.0 {
status = "❌"
}
fmt.Printf(" %s RPS: %8.0f Avg: %6.2fms P99: %6.2fms Success: %.1f%%\n",
status, rps, avgLat, float64(p99)/1e6, successRate)
fmt.Println()
return BenchResult{
Concurrency: conns,
TotalReqs: total,
SuccessReqs: success,
RPS: rps,
AvgLatency: avgLat,
P99Latency: float64(p99) / 1e6,
SuccessRate: successRate,
}
}
func printSummary(results []BenchResult) {
if len(results) <= 1 {
return
}
fmt.Println("═══════════════════════════════════════════════════════════════════════════")
fmt.Println(" 📊 测试结果汇总")
fmt.Println("═══════════════════════════════════════════════════════════════════════════")
fmt.Println()
fmt.Println("┌──────────────┬──────────────┬──────────────┬──────────────┬──────────────┐")
fmt.Println("│ 并发数 │ RPS │ 平均延迟 │ P99延迟 │ 成功率 │")
fmt.Println("├──────────────┼──────────────┼──────────────┼──────────────┼──────────────┤")
allPassed := true
for _, r := range results {
status := "✅"
if r.SuccessRate < 99.0 {
status = "⚠️"
allPassed = false
}
if r.SuccessRate < 90.0 {
status = "❌"
allPassed = false
}
fmt.Printf("│ %s %6d │ %10.0f │ %8.2fms │ %8.2fms │ %8.1f%% │\n",
status, r.Concurrency, r.RPS, r.AvgLatency, r.P99Latency, r.SuccessRate)
}
fmt.Println("└──────────────┴──────────────┴──────────────┴──────────────┴──────────────┘")
fmt.Println()
if allPassed {
fmt.Println("🎉 所有高并发测试通过!v-hono uSockets 后端表现优秀!")
} else {
fmt.Println("⚠️ 部分测试未达到 99% 成功率,请检查系统配置")
fmt.Println(" - macOS: sudo sysctl -w kern.ipc.somaxconn=8192")
fmt.Println(" - ulimit -n 65535")
}
fmt.Println()
}