- 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
246 lines
7.4 KiB
Go
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()
|
|
}
|