238 lines
9.1 KiB
V
238 lines
9.1 KiB
V
// HTTP 压测工具 - veb vs v-hono 性能对比
|
|
// 运行: v run http_benchmark.v
|
|
//
|
|
// 使用前请先启动服务器:
|
|
// 终端1: v run server_veb.v (端口 8080)
|
|
// 终端2: v run server_hono.v (端口 8081)
|
|
|
|
module main
|
|
|
|
import net.http
|
|
import time
|
|
|
|
// 测试配置
|
|
const veb_base_url = 'http://127.0.0.1:8080'
|
|
const hono_base_url = 'http://127.0.0.1:8081'
|
|
const requests_per_endpoint = 200
|
|
|
|
// 测试端点
|
|
struct Endpoint {
|
|
path string
|
|
name string
|
|
}
|
|
|
|
const test_endpoints = [
|
|
Endpoint{path: '/', name: '首页 (静态)'},
|
|
Endpoint{path: '/api/health', name: '健康检查 (静态)'},
|
|
Endpoint{path: '/api/users', name: '用户列表 (静态)'},
|
|
Endpoint{path: '/api/users/123', name: '单个用户 (动态)'},
|
|
Endpoint{path: '/api/users/456/posts', name: '用户帖子 (动态)'},
|
|
]
|
|
|
|
struct BenchmarkResult {
|
|
endpoint string
|
|
total_requests int
|
|
success_count int
|
|
error_count int
|
|
total_time_ms i64
|
|
avg_time_ms f64
|
|
min_time_ms f64
|
|
max_time_ms f64
|
|
rps f64
|
|
}
|
|
|
|
fn main() {
|
|
println('')
|
|
println('╔═══════════════════════════════════════════════════════════════╗')
|
|
println('║ HTTP 压测工具 - veb vs v-hono 性能对比 ║')
|
|
println('╠═══════════════════════════════════════════════════════════════╣')
|
|
println('║ 请确保已启动以下服务器: ║')
|
|
println('║ - veb: v run server_veb.v (端口 8080) ║')
|
|
println('║ - v-hono: v run server_hono.v (端口 8081) ║')
|
|
println('╚═══════════════════════════════════════════════════════════════╝')
|
|
println('')
|
|
|
|
// 检查服务器是否可用
|
|
println('检查服务器状态...')
|
|
veb_available := check_server(veb_base_url)
|
|
hono_available := check_server(hono_base_url)
|
|
|
|
if !veb_available {
|
|
println('⚠️ veb 服务器 (${veb_base_url}) 不可用')
|
|
} else {
|
|
println('✅ veb 服务器 (${veb_base_url}) 已就绪')
|
|
}
|
|
|
|
if !hono_available {
|
|
println('⚠️ v-hono 服务器 (${hono_base_url}) 不可用')
|
|
} else {
|
|
println('✅ v-hono 服务器 (${hono_base_url}) 已就绪')
|
|
}
|
|
|
|
if !veb_available && !hono_available {
|
|
println('')
|
|
println('❌ 没有可用的服务器,请先启动服务器后再运行测试')
|
|
return
|
|
}
|
|
|
|
println('')
|
|
println('开始压测 (每端点 ${requests_per_endpoint} 次请求)...')
|
|
println('─────────────────────────────────────────────────────────────────')
|
|
|
|
mut veb_results := []BenchmarkResult{}
|
|
mut hono_results := []BenchmarkResult{}
|
|
|
|
for endpoint in test_endpoints {
|
|
println('')
|
|
println('测试端点: ${endpoint.name} (${endpoint.path})')
|
|
|
|
if veb_available {
|
|
result := run_benchmark('veb', veb_base_url, endpoint)
|
|
veb_results << result
|
|
print_single_result('veb', result)
|
|
}
|
|
|
|
if hono_available {
|
|
result := run_benchmark('v-hono', hono_base_url, endpoint)
|
|
hono_results << result
|
|
print_single_result('v-hono', result)
|
|
}
|
|
}
|
|
|
|
// 打印对比结果
|
|
if veb_available && hono_available {
|
|
print_comparison_table(veb_results, hono_results)
|
|
}
|
|
|
|
// 打印总结
|
|
print_summary(veb_results, hono_results, veb_available, hono_available)
|
|
}
|
|
|
|
fn check_server(base_url string) bool {
|
|
http.get(base_url) or { return false }
|
|
return true
|
|
}
|
|
|
|
fn run_benchmark(name string, base_url string, endpoint Endpoint) BenchmarkResult {
|
|
url := '${base_url}${endpoint.path}'
|
|
|
|
mut success_count := 0
|
|
mut error_count := 0
|
|
mut min_time := f64(999999.0)
|
|
mut max_time := f64(0.0)
|
|
mut total_req_time := f64(0.0)
|
|
|
|
start_time := time.now()
|
|
|
|
for _ in 0 .. requests_per_endpoint {
|
|
req_start := time.now()
|
|
|
|
resp := http.get(url) or {
|
|
error_count++
|
|
continue
|
|
}
|
|
|
|
req_time := f64(time.since(req_start).microseconds()) / 1000.0
|
|
|
|
if resp.status_code >= 200 && resp.status_code < 300 {
|
|
success_count++
|
|
} else {
|
|
error_count++
|
|
}
|
|
|
|
total_req_time += req_time
|
|
if req_time < min_time {
|
|
min_time = req_time
|
|
}
|
|
if req_time > max_time {
|
|
max_time = req_time
|
|
}
|
|
}
|
|
|
|
total_time := time.since(start_time)
|
|
total_time_ms := total_time.milliseconds()
|
|
total_requests := success_count + error_count
|
|
avg_time := if total_requests > 0 { total_req_time / f64(total_requests) } else { 0.0 }
|
|
rps := if total_time_ms > 0 { f64(total_requests) * 1000.0 / f64(total_time_ms) } else { 0.0 }
|
|
|
|
return BenchmarkResult{
|
|
endpoint: endpoint.name
|
|
total_requests: total_requests
|
|
success_count: success_count
|
|
error_count: error_count
|
|
total_time_ms: total_time_ms
|
|
avg_time_ms: avg_time
|
|
min_time_ms: min_time
|
|
max_time_ms: max_time
|
|
rps: rps
|
|
}
|
|
}
|
|
|
|
fn print_single_result(name string, r BenchmarkResult) {
|
|
println(' ${name}: ${r.rps:.0} req/s | avg: ${r.avg_time_ms:.2}ms | min: ${r.min_time_ms:.2}ms | max: ${r.max_time_ms:.2}ms | 成功: ${r.success_count}/${r.total_requests}')
|
|
}
|
|
|
|
fn print_comparison_table(veb_results []BenchmarkResult, hono_results []BenchmarkResult) {
|
|
println('')
|
|
println('╔═══════════════════════════════════════════════════════════════════════════════════════╗')
|
|
println('║ 性能对比表 ║')
|
|
println('╠═══════════════════════════════════════════════════════════════════════════════════════╣')
|
|
println('║ 端点 │ veb (req/s) │ v-hono (req/s) │ 差异 │ 胜出 ║')
|
|
println('╠═══════════════════════════════════════════════════════════════════════════════════════╣')
|
|
|
|
for i, veb_r in veb_results {
|
|
if i >= hono_results.len {
|
|
break
|
|
}
|
|
hono_r := hono_results[i]
|
|
|
|
diff := hono_r.rps - veb_r.rps
|
|
diff_pct := if veb_r.rps > 0 { (diff / veb_r.rps) * 100.0 } else { 0.0 }
|
|
winner := if hono_r.rps > veb_r.rps { 'v-hono' } else { 'veb' }
|
|
|
|
name := veb_r.endpoint
|
|
veb_rps := '${veb_r.rps:.0}'
|
|
hono_rps := '${hono_r.rps:.0}'
|
|
diff_str := if diff > 0 { '+${diff_pct:.1}%' } else { '${diff_pct:.1}%' }
|
|
|
|
println('║ ${name:-23} │ ${veb_rps:-12} │ ${hono_rps:-14} │ ${diff_str:-9} │ ${winner:-14} ║')
|
|
}
|
|
|
|
println('╚═══════════════════════════════════════════════════════════════════════════════════════╝')
|
|
}
|
|
|
|
fn print_summary(veb_results []BenchmarkResult, hono_results []BenchmarkResult, veb_available bool, hono_available bool) {
|
|
println('')
|
|
println('╔═══════════════════════════════════════════════════════════════╗')
|
|
println('║ 测试总结 ║')
|
|
println('╠═══════════════════════════════════════════════════════════════╣')
|
|
|
|
if veb_available && veb_results.len > 0 {
|
|
mut total_rps := f64(0.0)
|
|
for r in veb_results {
|
|
total_rps += r.rps
|
|
}
|
|
avg_rps := total_rps / f64(veb_results.len)
|
|
println('║ veb 平均吞吐量: ${avg_rps:-40.0} req/s ║')
|
|
}
|
|
|
|
if hono_available && hono_results.len > 0 {
|
|
mut total_rps := f64(0.0)
|
|
for r in hono_results {
|
|
total_rps += r.rps
|
|
}
|
|
avg_rps := total_rps / f64(hono_results.len)
|
|
println('║ v-hono 平均吞吐量: ${avg_rps:-40.0} req/s ║')
|
|
}
|
|
|
|
println('╠═══════════════════════════════════════════════════════════════╣')
|
|
println('║ 测试配置: ║')
|
|
println('║ - 每端点请求数: ${requests_per_endpoint:-44} ║')
|
|
println('╚═══════════════════════════════════════════════════════════════╝')
|
|
|
|
println('')
|
|
println('提示: 使用 wrk 或 ab 可以获得更准确的压测结果:')
|
|
println(' wrk -t4 -c100 -d10s http://127.0.0.1:8080/')
|
|
println(' wrk -t4 -c100 -d10s http://127.0.0.1:8081/')
|
|
}
|