Files
go-omni/PERFORMANCE.md

6.1 KiB
Raw Blame History

GoOmni 性能基线

这轮测量显示 native 与标准库处于相同吞吐量级,在本机短时测试中,native 的空闲长连接堆内存更少。当前 native 仅实现 HTTP 的部分能力,尚不能据此判断生产容量或替代完整标准库服务端。

运行方式

# race、vet、build,以及进程内和真实 TCP benchmark
python3 scripts/verifyPerformance.py

# 另加独立服务进程的并发、延迟和空闲长连接内存矩阵
python3 scripts/verifyPerformance.py --load --output /tmp/goOmniPerf.json

# 只运行独立进程矩阵,默认每档 2 秒、3 轮
go run ./internal/perfcheck --duration 2s --count 3 --output /tmp/goOmniPerf.json

可通过 --concurrency 1,32,128 / --idle 128,1024 调整矩阵;传空字符串可跳过对应场景。工具只监听本机随机端口,每个场景启动独立服务进程,并在结束后关闭客户端、检查连接排空、关闭服务。响应状态、完整响应体、requestId 或传输错误均计入失败,不能把快速返回的错误页算成成功吞吐。

2026-09-21 本机测量

环境:Go 1.25.0、darwin/arm64、Apple M2 Max、GOMAXPROCS=12。网络实现来自 3d5f225 工作树(native 与 v0.5.0 相同);本次新增测量工具,不修改服务端实现。原始测量值见 tcpBaseline.json。报告时间为 UTC,北京时间是 9 月 21 日。

每个并发档位持续约 2 秒、重复 3 轮,每轮交替标准库/native 的先后顺序。下表为各指标的三轮中位数;全部流量场景共完成 2,660,828 次请求,错误 0。另有 128 / 1,024 条空闲长连接的建立、保持和回收测试。

并发请求 标准库成功请求/秒 native 成功请求/秒 标准库 P95 native P95 标准库 P99 native P99
1 19,731 21,497 0.074 ms 0.070 ms 0.139 ms 0.119 ms
32 90,099 88,812 1.016 ms 0.983 ms 1.507 ms 1.507 ms
128 112,422 112,105 3.277 ms 3.408 ms 4.719 ms 4.981 ms

128 并发时,两者吞吐差约 0.3%,native 的尾延迟略高。基于这组结果,暂时没有理由仅为健康接口吞吐就改成手写事件循环。

空闲 Keep-Alive 连接 标准库新增堆内存 native 新增堆内存 标准库约每连接 native 约每连接
128 1.275 MiB 0.658 MiB 10,444 B 5,389 B
1,024 9.871 MiB 5.137 MiB 10,108 B 5,260 B

1,024 条空闲连接时,native 的新增堆内存约少 48%。这是服务端 Go 堆内存增量,不包括 goroutine 栈、进程其他内存和内核 socket 缓冲区,不能解释为整个进程内存减半。同档服务端 StackInuse 分别约为标准库 8.75 MiB、native 8.69 MiB,原始报告单独记录。

连接断开后,两者连接数都回到 0,goroutine 分别回到 2 / 3 的初始基线。一次 GC 后仍有对象池缓存;第二次 GC 后,总堆内存中位数回到约 2.10 / 2.08 MiB(启动基线约 1.54 MiB)。堆内存不会立刻精确回到启动数值,不把缓存保留解释为泄漏,也不把这轮短测解释为长期无泄漏证明。

128 并发时,服务端单独累计分配约为标准库 4,454 B/请求、47 次/请求,native 4,297 B/请求、55 次/请求。native 的分配字节较少、次数较多;具体来源需用分配 profile 确认,不能仅凭总量归因于 HTTP 桥接或 JSON。

统计边界

  • 同一台机器上,压测客户端和服务端是两个独立进程。两者使用同一健康接口、相同小型 JSON 响应、固定 requestId=perfCheck 和 Keep-Alive;不启用访问日志、TLS 或数据库。
  • 并发模型为闭环:每个 worker 等上一个请求完成后发下一个。实际经过时间包含最后请求排空;吞吐只计算成功响应。不能据此推断开放到达流量下的排队或过载表现。
  • 延迟从客户端发起请求到完整响应校验完成,包含失败请求。直方图使用每个 2 的幂区间内 16 档,报告桶上界,舍入误差至多约 6.25%。小幅差别不应过度解释。
  • 服务端 runtime.MemStats 通过独立 stdin/stdout 控制通道读取,客户端内存不计入。累计分配差值包含少量采样开销。堆峰值每 200 ms 采样,可能错过瞬时峰值;这些指标不是进程 RSS。
  • 空闲场景在所有连接完成健康请求后做 GC 再采样。新增堆内存包括连接、缓冲区及分摊的运行时开销。after 为客户端断开并排空后一次 GC,afterReclaim 为第二次 GC,用于观察对象池缓存释放。
  • native 配置上限为 8,192 连接 / 4,096 活跃请求;本轮并发低于上限,未验证过载保护容量。标准库没有同样的并发闸门;比较包括各自真实实现的开销。
  • 可用 python3 scripts/verifyPerformance.py --load --tls --duration 2s 运行 TLS 版本的独立进程矩阵。该模式在每个子进程生成短期自签名证书,客户端仅用于本机基准验证;本报告的历史表格仍是无 TLS 数据。

benchmark 口径修正

BenchmarkTransportTCPApplicationRequest/{nethttp,native}/concurrency{1,32,128} 使用同一测试入口、客户端、应用与响应检查。原先独立的 BenchmarkNativeApplicationRequest 已合并,避免两个入口配置漂移。verifyPerformance.py 会一并运行。

并行 benchmark 的 ns/op 是总经过时间除以请求数,反映吞吐成本,不是单请求延迟。B/op / allocs/op 统计同一进程中的客户端与服务端总分配。此前报告的 native 15.4–16.7 µs/op、约 7.8 KB/op、100 allocs/op 应按这个含义理解,不能作为服务端延迟或独立内存指标。

BenchmarkTransportRouteDispatch 和 BenchmarkTransportApplicationRequest 继续保留,分别测进程内路由分发和完整框架处理链;不包含 TCP,不能直接与上述网络延迟比较。

后续优先补 Linux 目标环境、持续压测、大请求体/慢客户端、连接反复建立回收和协议边界验证,再通过 profile 决定是否优化对象分配或事件状态机。