test: validate native TLS on Linux
This commit is contained in:
@@ -9,6 +9,7 @@
|
||||
- native 响应实现 `http.Flusher`:HTTP/1.1 流式响应自动使用 chunked framing,普通响应继续自动生成 `Content-Length`。
|
||||
- native 在长 Handler 运行期间监测客户端断开并取消请求 context,流式写失败同步取消;短请求延迟启动监测,管线数据保留给下一次请求。补充断开、监测退出和长连接复用验收。
|
||||
- native 增加 `ServeTLS` / `RunTLS` 和 `TLSConfig` 启动入口,App.RunWith 可以直接启用 TLS;补充真实 TLS 客户端握手、请求和优雅退出验收。
|
||||
- native 请求补齐 `Request.TLS` 连接状态;Linux/arm64 容器通过全量 race、vet、build,以及 TLS 并发、Keep-Alive、慢握手和连接上限回收验收。
|
||||
- 补充慢请求体超时、大请求体和同连接管线请求验收,确认请求体未完整读取时不会进入业务 Handler,连续请求不会串线。
|
||||
- 补充 `MaxConnections` 满载拒绝与槽位释放验收,确认请求完成后连接容量可再次使用。
|
||||
- 增加 8 并发、800 次建连/断连的状态池 churn 验收,覆盖连接对象回收与容量复用。
|
||||
|
||||
@@ -54,6 +54,12 @@ go run ./internal/perfcheck --duration 2s --count 3 --output /tmp/goOmniPerf.jso
|
||||
|
||||
## benchmark 口径修正
|
||||
|
||||
## TLS 验收记录
|
||||
|
||||
macOS arm64 本机的 5 秒 TLS 矩阵见 [tlsBaseline.json](performance/tlsBaseline.json):1 / 32 / 128 并发和 128 / 1,024 条空闲连接均为 0 错误;native 在 128 并发约 114,232 req/s,1,024 条空闲 TLS 连接的服务端堆增量约 8.94 MiB,连接关闭后 goroutine 回到基线。
|
||||
|
||||
Linux arm64 容器使用 Go 1.25.14、GOMAXPROCS=4 运行 3 秒矩阵,见 [tlsBaselineLinux.json](performance/tlsBaselineLinux.json):1 / 32 / 128 并发和 128 / 512 条空闲连接均为 0 错误;native 在 128 并发约 99,876 req/s,512 条空闲 TLS 连接的服务端堆增量约 4.47 MiB,连接关闭后 goroutine 回到基线。容器验证同时通过全量 race、vet、build。
|
||||
|
||||
`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 应按这个含义理解,不能作为服务端延迟或独立内存指标。
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
- native 已支持受 `MaxBodyBytes` 约束的 `Content-Length` / chunked 请求体,仍使用标准 `http.Request` / `http.ResponseWriter` 作为桥接;解析器、连接抽象和生产压测将在后续阶段继续下沉。
|
||||
- native 响应已支持标准 `http.Flusher`;HTTP/1.1 流式响应使用 chunked framing,普通响应继续走 `Content-Length`,HTTP/1.0 回退到关闭连接分帧。
|
||||
- native 长请求已补客户端断开及流式写失败取消,监测退出后再复用 Reader;已验收普通/流式断开、慢 Handler 后连续 Keep-Alive 和管线数据不被误消费。短请求延迟启动监测,已有管线数据时取消依赖后续写失败或 Handler 返回。
|
||||
- 已补充慢请求体超时、大请求体、HTTP/1.0 Keep-Alive、HEAD/204、管线请求和基础 TLS 客户端验收;Linux、慢客户端规模、TLS 吞吐和持续运行压测仍待在目标环境验证。
|
||||
- 已补充慢请求体超时、大请求体、HTTP/1.0 Keep-Alive、HEAD/204、管线请求和基础 TLS 客户端验收;Linux/arm64 容器已通过全量 race、vet、build,以及 3 秒 TLS 并发/空闲连接矩阵。原始报告见 [tlsBaselineLinux.json](performance/tlsBaselineLinux.json);慢客户端规模和持续生产压测仍待真实部署环境验证。
|
||||
- 已验证 `MaxConnections` 满载时快速拒绝新连接、请求完成后释放容量;后续仍需在目标部署环境观察文件描述符、内核 socket 缓冲和反向代理联动。
|
||||
- 已用 8 个并发 worker 完成 800 次建连/断连 race 验收;真实部署仍需补文件描述符和跨平台 socket 行为观测。
|
||||
- 已具备全量 race、vet、build 验收;生产压测、长连接规模和真实部署验证仍待完成。
|
||||
|
||||
592
performance/tlsBaseline.json
Normal file
592
performance/tlsBaseline.json
Normal file
@@ -0,0 +1,592 @@
|
||||
{
|
||||
"createdAt": "2026-09-20T21:27:15Z",
|
||||
"goVersion": "go1.25.0",
|
||||
"platform": "darwin/arm64",
|
||||
"gomaxprocs": 12,
|
||||
"duration": "5s",
|
||||
"tls": true,
|
||||
"notes": [
|
||||
"Loopback HTTP/1.1 health response, fixed requestId, optional TLS, no access logs or database.",
|
||||
"Each case starts a fresh server process; load client runs in the parent process on the same machine.",
|
||||
"Closed-loop concurrency; throughput is successful responses / actual elapsed time, including drain.",
|
||||
"Latency percentiles include failures and are histogram upper bounds with \u003c=6.25% rounding.",
|
||||
"Memory is server-only runtime.MemStats (not RSS or kernel socket memory); sampling interval 200ms.",
|
||||
"Idle memory measured after a forced GC; delta includes heap growth amortized across connections, excluding stacks.",
|
||||
"After is after closing clients and one forced GC; afterReclaim is a second GC to observe pooled-cache release.",
|
||||
"Native limits: 8192 connections / 4096 active requests. These cases do not benchmark overload rejection."
|
||||
],
|
||||
"results": [
|
||||
{
|
||||
"adapter": "nethttp",
|
||||
"scenario": "traffic",
|
||||
"concurrency": 1,
|
||||
"run": 1,
|
||||
"requests": 86935,
|
||||
"errors": 0,
|
||||
"elapsedSeconds": 5.000022,
|
||||
"requestsPerSecond": 17386.92349753661,
|
||||
"p50Millis": 0.0512,
|
||||
"p95Millis": 0.1024,
|
||||
"p99Millis": 0.180224,
|
||||
"serverBytesPerRequest": 4514.537988152068,
|
||||
"serverAllocsPerRequest": 49.1346753321447,
|
||||
"sampledPeakHeapAlloc": 3349712,
|
||||
"before": {
|
||||
"heapAlloc": 1678936,
|
||||
"heapInuse": 3661824,
|
||||
"stackInuse": 655360,
|
||||
"totalAlloc": 3167032,
|
||||
"mallocs": 24353,
|
||||
"numGc": 2,
|
||||
"goroutines": 3,
|
||||
"connections": 1,
|
||||
"accepted": 1
|
||||
},
|
||||
"during": {
|
||||
"heapAlloc": 3337216,
|
||||
"heapInuse": 5341184,
|
||||
"stackInuse": 753664,
|
||||
"totalAlloc": 395638392,
|
||||
"mallocs": 4295876,
|
||||
"numGc": 238,
|
||||
"goroutines": 3,
|
||||
"connections": 1,
|
||||
"accepted": 1
|
||||
},
|
||||
"after": {
|
||||
"heapAlloc": 1774168,
|
||||
"heapInuse": 3792896,
|
||||
"stackInuse": 688128,
|
||||
"totalAlloc": 395642616,
|
||||
"mallocs": 4295888,
|
||||
"numGc": 239,
|
||||
"goroutines": 2,
|
||||
"connections": 0,
|
||||
"accepted": 1
|
||||
},
|
||||
"afterReclaim": {
|
||||
"heapAlloc": 1741008,
|
||||
"heapInuse": 3620864,
|
||||
"stackInuse": 688128,
|
||||
"totalAlloc": 395644800,
|
||||
"mallocs": 4295894,
|
||||
"numGc": 240,
|
||||
"goroutines": 2,
|
||||
"connections": 0,
|
||||
"accepted": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"adapter": "native",
|
||||
"scenario": "traffic",
|
||||
"concurrency": 1,
|
||||
"run": 1,
|
||||
"requests": 91798,
|
||||
"errors": 0,
|
||||
"elapsedSeconds": 5.000019125,
|
||||
"requestsPerSecond": 18359.52977479861,
|
||||
"p50Millis": 0.049152,
|
||||
"p95Millis": 0.090112,
|
||||
"p99Millis": 0.16384,
|
||||
"serverBytesPerRequest": 4635.560426153075,
|
||||
"serverAllocsPerRequest": 60.11798731998518,
|
||||
"sampledPeakHeapAlloc": 3267488,
|
||||
"before": {
|
||||
"heapAlloc": 1653880,
|
||||
"heapInuse": 3678208,
|
||||
"stackInuse": 622592,
|
||||
"totalAlloc": 3145792,
|
||||
"mallocs": 24330,
|
||||
"numGc": 2,
|
||||
"goroutines": 4,
|
||||
"connections": 1,
|
||||
"accepted": 1
|
||||
},
|
||||
"during": {
|
||||
"heapAlloc": 1828360,
|
||||
"heapInuse": 4022272,
|
||||
"stackInuse": 688128,
|
||||
"totalAlloc": 428680968,
|
||||
"mallocs": 5543041,
|
||||
"numGc": 264,
|
||||
"goroutines": 4,
|
||||
"connections": 1,
|
||||
"accepted": 1
|
||||
},
|
||||
"after": {
|
||||
"heapAlloc": 1687208,
|
||||
"heapInuse": 3817472,
|
||||
"stackInuse": 655360,
|
||||
"totalAlloc": 428685256,
|
||||
"mallocs": 5543054,
|
||||
"numGc": 265,
|
||||
"goroutines": 3,
|
||||
"connections": 0,
|
||||
"accepted": 1
|
||||
},
|
||||
"afterReclaim": {
|
||||
"heapAlloc": 1668072,
|
||||
"heapInuse": 3588096,
|
||||
"stackInuse": 655360,
|
||||
"totalAlloc": 428687440,
|
||||
"mallocs": 5543060,
|
||||
"numGc": 266,
|
||||
"goroutines": 3,
|
||||
"connections": 0,
|
||||
"accepted": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"adapter": "nethttp",
|
||||
"scenario": "traffic",
|
||||
"concurrency": 32,
|
||||
"run": 1,
|
||||
"requests": 443035,
|
||||
"errors": 0,
|
||||
"elapsedSeconds": 5.000301084,
|
||||
"requestsPerSecond": 88601.66469127762,
|
||||
"p50Millis": 0.278528,
|
||||
"p95Millis": 1.015808,
|
||||
"p99Millis": 1.507328,
|
||||
"serverBytesPerRequest": 4524.947022244292,
|
||||
"serverAllocsPerRequest": 49.153904319071856,
|
||||
"sampledPeakHeapAlloc": 4957328,
|
||||
"before": {
|
||||
"heapAlloc": 2174976,
|
||||
"heapInuse": 5406720,
|
||||
"stackInuse": 1277952,
|
||||
"totalAlloc": 4859520,
|
||||
"mallocs": 39778,
|
||||
"numGc": 4,
|
||||
"goroutines": 34,
|
||||
"connections": 32,
|
||||
"accepted": 32
|
||||
},
|
||||
"during": {
|
||||
"heapAlloc": 3437936,
|
||||
"heapInuse": 6717440,
|
||||
"stackInuse": 2490368,
|
||||
"totalAlloc": 2009569424,
|
||||
"mallocs": 21816678,
|
||||
"numGc": 1167,
|
||||
"goroutines": 34,
|
||||
"connections": 32,
|
||||
"accepted": 32
|
||||
},
|
||||
"after": {
|
||||
"heapAlloc": 2301792,
|
||||
"heapInuse": 4833280,
|
||||
"stackInuse": 2195456,
|
||||
"totalAlloc": 2009575408,
|
||||
"mallocs": 21816709,
|
||||
"numGc": 1168,
|
||||
"goroutines": 2,
|
||||
"connections": 0,
|
||||
"accepted": 32
|
||||
},
|
||||
"afterReclaim": {
|
||||
"heapAlloc": 1983832,
|
||||
"heapInuse": 3915776,
|
||||
"stackInuse": 2195456,
|
||||
"totalAlloc": 2009577336,
|
||||
"mallocs": 21816714,
|
||||
"numGc": 1169,
|
||||
"goroutines": 2,
|
||||
"connections": 0,
|
||||
"accepted": 32
|
||||
}
|
||||
},
|
||||
{
|
||||
"adapter": "native",
|
||||
"scenario": "traffic",
|
||||
"concurrency": 32,
|
||||
"run": 1,
|
||||
"requests": 422203,
|
||||
"errors": 0,
|
||||
"elapsedSeconds": 5.0001875,
|
||||
"requestsPerSecond": 84437.43359624014,
|
||||
"p50Millis": 0.294912,
|
||||
"p95Millis": 1.015808,
|
||||
"p99Millis": 1.507328,
|
||||
"serverBytesPerRequest": 4655.5327176737255,
|
||||
"serverAllocsPerRequest": 60.24485614739829,
|
||||
"sampledPeakHeapAlloc": 3953128,
|
||||
"before": {
|
||||
"heapAlloc": 1991704,
|
||||
"heapInuse": 5013504,
|
||||
"stackInuse": 1081344,
|
||||
"totalAlloc": 4644928,
|
||||
"mallocs": 39578,
|
||||
"numGc": 3,
|
||||
"goroutines": 35,
|
||||
"connections": 32,
|
||||
"accepted": 32
|
||||
},
|
||||
"during": {
|
||||
"heapAlloc": 2969168,
|
||||
"heapInuse": 6266880,
|
||||
"stackInuse": 1212416,
|
||||
"totalAlloc": 1970224808,
|
||||
"mallocs": 25475137,
|
||||
"numGc": 1687,
|
||||
"goroutines": 35,
|
||||
"connections": 32,
|
||||
"accepted": 32
|
||||
},
|
||||
"after": {
|
||||
"heapAlloc": 2053344,
|
||||
"heapInuse": 5062656,
|
||||
"stackInuse": 851968,
|
||||
"totalAlloc": 1970231512,
|
||||
"mallocs": 25475175,
|
||||
"numGc": 1688,
|
||||
"goroutines": 3,
|
||||
"connections": 0,
|
||||
"accepted": 32
|
||||
},
|
||||
"afterReclaim": {
|
||||
"heapAlloc": 1754136,
|
||||
"heapInuse": 3792896,
|
||||
"stackInuse": 851968,
|
||||
"totalAlloc": 1970233696,
|
||||
"mallocs": 25475181,
|
||||
"numGc": 1689,
|
||||
"goroutines": 3,
|
||||
"connections": 0,
|
||||
"accepted": 32
|
||||
}
|
||||
},
|
||||
{
|
||||
"adapter": "nethttp",
|
||||
"scenario": "traffic",
|
||||
"concurrency": 128,
|
||||
"run": 1,
|
||||
"requests": 564759,
|
||||
"errors": 0,
|
||||
"elapsedSeconds": 5.000520667,
|
||||
"requestsPerSecond": 112940.03916972512,
|
||||
"p50Millis": 0.8192,
|
||||
"p95Millis": 3.2768,
|
||||
"p99Millis": 4.718592,
|
||||
"serverBytesPerRequest": 4499.995148373023,
|
||||
"serverAllocsPerRequest": 49.13783401415471,
|
||||
"sampledPeakHeapAlloc": 7449240,
|
||||
"before": {
|
||||
"heapAlloc": 3409760,
|
||||
"heapInuse": 6938624,
|
||||
"stackInuse": 2457600,
|
||||
"totalAlloc": 9389504,
|
||||
"mallocs": 81651,
|
||||
"numGc": 8,
|
||||
"goroutines": 118,
|
||||
"connections": 116,
|
||||
"accepted": 116
|
||||
},
|
||||
"during": {
|
||||
"heapAlloc": 5261072,
|
||||
"heapInuse": 9068544,
|
||||
"stackInuse": 3276800,
|
||||
"totalAlloc": 2550802264,
|
||||
"mallocs": 27832685,
|
||||
"numGc": 775,
|
||||
"goroutines": 130,
|
||||
"connections": 128,
|
||||
"accepted": 128
|
||||
},
|
||||
"after": {
|
||||
"heapAlloc": 3142160,
|
||||
"heapInuse": 6086656,
|
||||
"stackInuse": 2162688,
|
||||
"totalAlloc": 2550814744,
|
||||
"mallocs": 27832752,
|
||||
"numGc": 776,
|
||||
"goroutines": 2,
|
||||
"connections": 0,
|
||||
"accepted": 128
|
||||
},
|
||||
"afterReclaim": {
|
||||
"heapAlloc": 2014424,
|
||||
"heapInuse": 4038656,
|
||||
"stackInuse": 2162688,
|
||||
"totalAlloc": 2550816928,
|
||||
"mallocs": 27832758,
|
||||
"numGc": 777,
|
||||
"goroutines": 2,
|
||||
"connections": 0,
|
||||
"accepted": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"adapter": "native",
|
||||
"scenario": "traffic",
|
||||
"concurrency": 128,
|
||||
"run": 1,
|
||||
"requests": 571218,
|
||||
"errors": 0,
|
||||
"elapsedSeconds": 5.000520459,
|
||||
"requestsPerSecond": 114231.70941574985,
|
||||
"p50Millis": 0.720896,
|
||||
"p95Millis": 3.538944,
|
||||
"p99Millis": 5.24288,
|
||||
"serverBytesPerRequest": 4630.001169430935,
|
||||
"serverAllocsPerRequest": 60.118471406713375,
|
||||
"sampledPeakHeapAlloc": 6594168,
|
||||
"before": {
|
||||
"heapAlloc": 2900712,
|
||||
"heapInuse": 6209536,
|
||||
"stackInuse": 1966080,
|
||||
"totalAlloc": 9196776,
|
||||
"mallocs": 86400,
|
||||
"numGc": 6,
|
||||
"goroutines": 131,
|
||||
"connections": 128,
|
||||
"accepted": 128
|
||||
},
|
||||
"during": {
|
||||
"heapAlloc": 5161328,
|
||||
"heapInuse": 8462336,
|
||||
"stackInuse": 1998848,
|
||||
"totalAlloc": 2653936784,
|
||||
"mallocs": 34427153,
|
||||
"numGc": 1026,
|
||||
"goroutines": 131,
|
||||
"connections": 128,
|
||||
"accepted": 128
|
||||
},
|
||||
"after": {
|
||||
"heapAlloc": 2950048,
|
||||
"heapInuse": 6201344,
|
||||
"stackInuse": 851968,
|
||||
"totalAlloc": 2653948208,
|
||||
"mallocs": 34427217,
|
||||
"numGc": 1027,
|
||||
"goroutines": 3,
|
||||
"connections": 0,
|
||||
"accepted": 128
|
||||
},
|
||||
"afterReclaim": {
|
||||
"heapAlloc": 1824888,
|
||||
"heapInuse": 3809280,
|
||||
"stackInuse": 851968,
|
||||
"totalAlloc": 2653950392,
|
||||
"mallocs": 34427223,
|
||||
"numGc": 1028,
|
||||
"goroutines": 3,
|
||||
"connections": 0,
|
||||
"accepted": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"adapter": "nethttp",
|
||||
"scenario": "idle",
|
||||
"concurrency": 128,
|
||||
"run": 1,
|
||||
"errors": 0,
|
||||
"idleHeapDelta": 1857928,
|
||||
"idleHeapPerConnection": 14515.0625,
|
||||
"before": {
|
||||
"heapAlloc": 1632120,
|
||||
"heapInuse": 3538944,
|
||||
"stackInuse": 524288,
|
||||
"totalAlloc": 3074624,
|
||||
"mallocs": 23744,
|
||||
"numGc": 1,
|
||||
"goroutines": 2,
|
||||
"connections": 0,
|
||||
"accepted": 0
|
||||
},
|
||||
"during": {
|
||||
"heapAlloc": 3490048,
|
||||
"heapInuse": 5808128,
|
||||
"stackInuse": 1835008,
|
||||
"totalAlloc": 9802696,
|
||||
"mallocs": 86273,
|
||||
"numGc": 5,
|
||||
"goroutines": 130,
|
||||
"connections": 128,
|
||||
"accepted": 128
|
||||
},
|
||||
"after": {
|
||||
"heapAlloc": 2814128,
|
||||
"heapInuse": 5062656,
|
||||
"stackInuse": 720896,
|
||||
"totalAlloc": 9818288,
|
||||
"mallocs": 86380,
|
||||
"numGc": 6,
|
||||
"goroutines": 2,
|
||||
"connections": 0,
|
||||
"accepted": 128
|
||||
},
|
||||
"afterReclaim": {
|
||||
"heapAlloc": 1732536,
|
||||
"heapInuse": 3661824,
|
||||
"stackInuse": 720896,
|
||||
"totalAlloc": 9820216,
|
||||
"mallocs": 86385,
|
||||
"numGc": 7,
|
||||
"goroutines": 2,
|
||||
"connections": 0,
|
||||
"accepted": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"adapter": "native",
|
||||
"scenario": "idle",
|
||||
"concurrency": 128,
|
||||
"run": 1,
|
||||
"errors": 0,
|
||||
"idleHeapDelta": 1212976,
|
||||
"idleHeapPerConnection": 9476.375,
|
||||
"before": {
|
||||
"heapAlloc": 1626208,
|
||||
"heapInuse": 3448832,
|
||||
"stackInuse": 491520,
|
||||
"totalAlloc": 3068760,
|
||||
"mallocs": 23727,
|
||||
"numGc": 1,
|
||||
"goroutines": 3,
|
||||
"connections": 0,
|
||||
"accepted": 0
|
||||
},
|
||||
"during": {
|
||||
"heapAlloc": 2839184,
|
||||
"heapInuse": 5210112,
|
||||
"stackInuse": 1802240,
|
||||
"totalAlloc": 9147832,
|
||||
"mallocs": 85868,
|
||||
"numGc": 5,
|
||||
"goroutines": 131,
|
||||
"connections": 128,
|
||||
"accepted": 128
|
||||
},
|
||||
"after": {
|
||||
"heapAlloc": 2838168,
|
||||
"heapInuse": 5169152,
|
||||
"stackInuse": 688128,
|
||||
"totalAlloc": 9163568,
|
||||
"mallocs": 85970,
|
||||
"numGc": 6,
|
||||
"goroutines": 3,
|
||||
"connections": 0,
|
||||
"accepted": 128
|
||||
},
|
||||
"afterReclaim": {
|
||||
"heapAlloc": 1729792,
|
||||
"heapInuse": 3563520,
|
||||
"stackInuse": 688128,
|
||||
"totalAlloc": 9166056,
|
||||
"mallocs": 85980,
|
||||
"numGc": 7,
|
||||
"goroutines": 3,
|
||||
"connections": 0,
|
||||
"accepted": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"adapter": "nethttp",
|
||||
"scenario": "idle",
|
||||
"concurrency": 1024,
|
||||
"run": 1,
|
||||
"errors": 0,
|
||||
"idleHeapDelta": 14527832,
|
||||
"idleHeapPerConnection": 14187.3359375,
|
||||
"before": {
|
||||
"heapAlloc": 1626760,
|
||||
"heapInuse": 3497984,
|
||||
"stackInuse": 491520,
|
||||
"totalAlloc": 3069240,
|
||||
"mallocs": 23740,
|
||||
"numGc": 1,
|
||||
"goroutines": 2,
|
||||
"connections": 0,
|
||||
"accepted": 0
|
||||
},
|
||||
"during": {
|
||||
"heapAlloc": 16154592,
|
||||
"heapInuse": 20807680,
|
||||
"stackInuse": 9207808,
|
||||
"totalAlloc": 56229808,
|
||||
"mallocs": 522226,
|
||||
"numGc": 12,
|
||||
"goroutines": 1026,
|
||||
"connections": 1024,
|
||||
"accepted": 1024
|
||||
},
|
||||
"after": {
|
||||
"heapAlloc": 10815896,
|
||||
"heapInuse": 14376960,
|
||||
"stackInuse": 720896,
|
||||
"totalAlloc": 56293624,
|
||||
"mallocs": 522449,
|
||||
"numGc": 13,
|
||||
"goroutines": 2,
|
||||
"connections": 0,
|
||||
"accepted": 1024
|
||||
},
|
||||
"afterReclaim": {
|
||||
"heapAlloc": 2202576,
|
||||
"heapInuse": 4227072,
|
||||
"stackInuse": 720896,
|
||||
"totalAlloc": 56296208,
|
||||
"mallocs": 522460,
|
||||
"numGc": 14,
|
||||
"goroutines": 2,
|
||||
"connections": 0,
|
||||
"accepted": 1024
|
||||
}
|
||||
},
|
||||
{
|
||||
"adapter": "native",
|
||||
"scenario": "idle",
|
||||
"concurrency": 1024,
|
||||
"run": 1,
|
||||
"errors": 0,
|
||||
"idleHeapDelta": 9372528,
|
||||
"idleHeapPerConnection": 9152.859375,
|
||||
"before": {
|
||||
"heapAlloc": 1625904,
|
||||
"heapInuse": 3457024,
|
||||
"stackInuse": 491520,
|
||||
"totalAlloc": 3068472,
|
||||
"mallocs": 23724,
|
||||
"numGc": 1,
|
||||
"goroutines": 3,
|
||||
"connections": 0,
|
||||
"accepted": 0
|
||||
},
|
||||
"during": {
|
||||
"heapAlloc": 10998432,
|
||||
"heapInuse": 14934016,
|
||||
"stackInuse": 9240576,
|
||||
"totalAlloc": 51165352,
|
||||
"mallocs": 519121,
|
||||
"numGc": 13,
|
||||
"goroutines": 1027,
|
||||
"connections": 1024,
|
||||
"accepted": 1024
|
||||
},
|
||||
"after": {
|
||||
"heapAlloc": 11019640,
|
||||
"heapInuse": 15032320,
|
||||
"stackInuse": 6553600,
|
||||
"totalAlloc": 51226512,
|
||||
"mallocs": 519340,
|
||||
"numGc": 14,
|
||||
"goroutines": 3,
|
||||
"connections": 0,
|
||||
"accepted": 1024
|
||||
},
|
||||
"afterReclaim": {
|
||||
"heapAlloc": 2196104,
|
||||
"heapInuse": 4153344,
|
||||
"stackInuse": 6553600,
|
||||
"totalAlloc": 51229000,
|
||||
"mallocs": 519350,
|
||||
"numGc": 15,
|
||||
"goroutines": 3,
|
||||
"connections": 0,
|
||||
"accepted": 1024
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
592
performance/tlsBaselineLinux.json
Normal file
592
performance/tlsBaselineLinux.json
Normal file
@@ -0,0 +1,592 @@
|
||||
{
|
||||
"createdAt": "2026-09-21T17:11:34Z",
|
||||
"goVersion": "go1.25.14",
|
||||
"platform": "linux/arm64",
|
||||
"gomaxprocs": 4,
|
||||
"duration": "3s",
|
||||
"tls": true,
|
||||
"notes": [
|
||||
"Loopback HTTP/1.1 health response, fixed requestId, optional TLS, no access logs or database.",
|
||||
"Each case starts a fresh server process; load client runs in the parent process on the same machine.",
|
||||
"Closed-loop concurrency; throughput is successful responses / actual elapsed time, including drain.",
|
||||
"Latency percentiles include failures and are histogram upper bounds with \u003c=6.25% rounding.",
|
||||
"Memory is server-only runtime.MemStats (not RSS or kernel socket memory); sampling interval 200ms.",
|
||||
"Idle memory measured after a forced GC; delta includes heap growth amortized across connections, excluding stacks.",
|
||||
"After is after closing clients and one forced GC; afterReclaim is a second GC to observe pooled-cache release.",
|
||||
"Native limits: 8192 connections / 4096 active requests. These cases do not benchmark overload rejection."
|
||||
],
|
||||
"results": [
|
||||
{
|
||||
"adapter": "nethttp",
|
||||
"scenario": "traffic",
|
||||
"concurrency": 1,
|
||||
"run": 1,
|
||||
"requests": 36326,
|
||||
"errors": 0,
|
||||
"elapsedSeconds": 3.000028418,
|
||||
"requestsPerSecond": 12108.551966390074,
|
||||
"p50Millis": 0.08192,
|
||||
"p95Millis": 0.1024,
|
||||
"p99Millis": 0.139264,
|
||||
"serverBytesPerRequest": 4475.917854979904,
|
||||
"serverAllocsPerRequest": 49.04346748885096,
|
||||
"sampledPeakHeapAlloc": 3669264,
|
||||
"before": {
|
||||
"heapAlloc": 1555696,
|
||||
"heapInuse": 3522560,
|
||||
"stackInuse": 491520,
|
||||
"totalAlloc": 3107240,
|
||||
"mallocs": 24268,
|
||||
"numGc": 2,
|
||||
"goroutines": 3,
|
||||
"connections": 1,
|
||||
"accepted": 1
|
||||
},
|
||||
"during": {
|
||||
"heapAlloc": 1789280,
|
||||
"heapInuse": 3874816,
|
||||
"stackInuse": 819200,
|
||||
"totalAlloc": 165699432,
|
||||
"mallocs": 1805821,
|
||||
"numGc": 82,
|
||||
"goroutines": 3,
|
||||
"connections": 1,
|
||||
"accepted": 1
|
||||
},
|
||||
"after": {
|
||||
"heapAlloc": 1645816,
|
||||
"heapInuse": 3629056,
|
||||
"stackInuse": 753664,
|
||||
"totalAlloc": 165700968,
|
||||
"mallocs": 1805830,
|
||||
"numGc": 83,
|
||||
"goroutines": 2,
|
||||
"connections": 0,
|
||||
"accepted": 1
|
||||
},
|
||||
"afterReclaim": {
|
||||
"heapAlloc": 1625904,
|
||||
"heapInuse": 3522560,
|
||||
"stackInuse": 720896,
|
||||
"totalAlloc": 165701872,
|
||||
"mallocs": 1805836,
|
||||
"numGc": 84,
|
||||
"goroutines": 2,
|
||||
"connections": 0,
|
||||
"accepted": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"adapter": "native",
|
||||
"scenario": "traffic",
|
||||
"concurrency": 1,
|
||||
"run": 1,
|
||||
"requests": 36410,
|
||||
"errors": 0,
|
||||
"elapsedSeconds": 3.000096335,
|
||||
"requestsPerSecond": 12136.276950586656,
|
||||
"p50Millis": 0.08192,
|
||||
"p95Millis": 0.1024,
|
||||
"p99Millis": 0.131072,
|
||||
"serverBytesPerRequest": 4807.387201318319,
|
||||
"serverAllocsPerRequest": 61.041444658060975,
|
||||
"sampledPeakHeapAlloc": 3473824,
|
||||
"before": {
|
||||
"heapAlloc": 1546544,
|
||||
"heapInuse": 3563520,
|
||||
"stackInuse": 524288,
|
||||
"totalAlloc": 3099040,
|
||||
"mallocs": 24253,
|
||||
"numGc": 2,
|
||||
"goroutines": 4,
|
||||
"connections": 1,
|
||||
"accepted": 1
|
||||
},
|
||||
"during": {
|
||||
"heapAlloc": 1987016,
|
||||
"heapInuse": 4014080,
|
||||
"stackInuse": 524288,
|
||||
"totalAlloc": 178136008,
|
||||
"mallocs": 2246772,
|
||||
"numGc": 96,
|
||||
"goroutines": 4,
|
||||
"connections": 1,
|
||||
"accepted": 1
|
||||
},
|
||||
"after": {
|
||||
"heapAlloc": 1557080,
|
||||
"heapInuse": 3637248,
|
||||
"stackInuse": 425984,
|
||||
"totalAlloc": 178137480,
|
||||
"mallocs": 2246784,
|
||||
"numGc": 97,
|
||||
"goroutines": 3,
|
||||
"connections": 0,
|
||||
"accepted": 1
|
||||
},
|
||||
"afterReclaim": {
|
||||
"heapAlloc": 1543112,
|
||||
"heapInuse": 3473408,
|
||||
"stackInuse": 425984,
|
||||
"totalAlloc": 178138128,
|
||||
"mallocs": 2246789,
|
||||
"numGc": 98,
|
||||
"goroutines": 3,
|
||||
"connections": 0,
|
||||
"accepted": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"adapter": "nethttp",
|
||||
"scenario": "traffic",
|
||||
"concurrency": 32,
|
||||
"run": 1,
|
||||
"requests": 297651,
|
||||
"errors": 0,
|
||||
"elapsedSeconds": 3.000748959,
|
||||
"requestsPerSecond": 99192.23636061586,
|
||||
"p50Millis": 0.172032,
|
||||
"p95Millis": 1.179648,
|
||||
"p99Millis": 2.097152,
|
||||
"serverBytesPerRequest": 4478.059122932562,
|
||||
"serverAllocsPerRequest": 49.0660605877353,
|
||||
"sampledPeakHeapAlloc": 4147936,
|
||||
"before": {
|
||||
"heapAlloc": 2046152,
|
||||
"heapInuse": 4554752,
|
||||
"stackInuse": 884736,
|
||||
"totalAlloc": 4736656,
|
||||
"mallocs": 39461,
|
||||
"numGc": 3,
|
||||
"goroutines": 34,
|
||||
"connections": 32,
|
||||
"accepted": 32
|
||||
},
|
||||
"during": {
|
||||
"heapAlloc": 3132976,
|
||||
"heapInuse": 5529600,
|
||||
"stackInuse": 1212416,
|
||||
"totalAlloc": 1337635432,
|
||||
"mallocs": 14644023,
|
||||
"numGc": 642,
|
||||
"goroutines": 34,
|
||||
"connections": 32,
|
||||
"accepted": 32
|
||||
},
|
||||
"after": {
|
||||
"heapAlloc": 1946392,
|
||||
"heapInuse": 4136960,
|
||||
"stackInuse": 884736,
|
||||
"totalAlloc": 1337638376,
|
||||
"mallocs": 14644047,
|
||||
"numGc": 643,
|
||||
"goroutines": 2,
|
||||
"connections": 0,
|
||||
"accepted": 32
|
||||
},
|
||||
"afterReclaim": {
|
||||
"heapAlloc": 1657656,
|
||||
"heapInuse": 3596288,
|
||||
"stackInuse": 884736,
|
||||
"totalAlloc": 1337639280,
|
||||
"mallocs": 14644053,
|
||||
"numGc": 644,
|
||||
"goroutines": 2,
|
||||
"connections": 0,
|
||||
"accepted": 32
|
||||
}
|
||||
},
|
||||
{
|
||||
"adapter": "native",
|
||||
"scenario": "traffic",
|
||||
"concurrency": 32,
|
||||
"run": 1,
|
||||
"requests": 271586,
|
||||
"errors": 0,
|
||||
"elapsedSeconds": 3.008536543,
|
||||
"requestsPerSecond": 90271.79697448004,
|
||||
"p50Millis": 0.172032,
|
||||
"p95Millis": 1.114112,
|
||||
"p99Millis": 2.097152,
|
||||
"serverBytesPerRequest": 4810.125264188876,
|
||||
"serverAllocsPerRequest": 61.068320900193676,
|
||||
"sampledPeakHeapAlloc": 3706424,
|
||||
"before": {
|
||||
"heapAlloc": 1833336,
|
||||
"heapInuse": 4136960,
|
||||
"stackInuse": 1048576,
|
||||
"totalAlloc": 4566744,
|
||||
"mallocs": 39398,
|
||||
"numGc": 3,
|
||||
"goroutines": 35,
|
||||
"connections": 32,
|
||||
"accepted": 32
|
||||
},
|
||||
"during": {
|
||||
"heapAlloc": 2032480,
|
||||
"heapInuse": 4661248,
|
||||
"stackInuse": 851968,
|
||||
"totalAlloc": 1310929424,
|
||||
"mallocs": 16624699,
|
||||
"numGc": 742,
|
||||
"goroutines": 35,
|
||||
"connections": 32,
|
||||
"accepted": 32
|
||||
},
|
||||
"after": {
|
||||
"heapAlloc": 1875360,
|
||||
"heapInuse": 4186112,
|
||||
"stackInuse": 524288,
|
||||
"totalAlloc": 1310933392,
|
||||
"mallocs": 16624734,
|
||||
"numGc": 743,
|
||||
"goroutines": 3,
|
||||
"connections": 0,
|
||||
"accepted": 32
|
||||
},
|
||||
"afterReclaim": {
|
||||
"heapAlloc": 1593792,
|
||||
"heapInuse": 3465216,
|
||||
"stackInuse": 524288,
|
||||
"totalAlloc": 1310934296,
|
||||
"mallocs": 16624740,
|
||||
"numGc": 744,
|
||||
"goroutines": 3,
|
||||
"connections": 0,
|
||||
"accepted": 32
|
||||
}
|
||||
},
|
||||
{
|
||||
"adapter": "nethttp",
|
||||
"scenario": "traffic",
|
||||
"concurrency": 128,
|
||||
"run": 1,
|
||||
"requests": 322494,
|
||||
"errors": 0,
|
||||
"elapsedSeconds": 3.001132293,
|
||||
"requestsPerSecond": 107457.44223012164,
|
||||
"p50Millis": 0.589824,
|
||||
"p95Millis": 2.752512,
|
||||
"p99Millis": 25.165824,
|
||||
"serverBytesPerRequest": 4475.7173528809835,
|
||||
"serverAllocsPerRequest": 49.07075790557344,
|
||||
"sampledPeakHeapAlloc": 7137248,
|
||||
"before": {
|
||||
"heapAlloc": 3503480,
|
||||
"heapInuse": 6340608,
|
||||
"stackInuse": 2228224,
|
||||
"totalAlloc": 9426048,
|
||||
"mallocs": 83598,
|
||||
"numGc": 5,
|
||||
"goroutines": 124,
|
||||
"connections": 122,
|
||||
"accepted": 122
|
||||
},
|
||||
"during": {
|
||||
"heapAlloc": 6849936,
|
||||
"heapInuse": 9125888,
|
||||
"stackInuse": 2162688,
|
||||
"totalAlloc": 1452818040,
|
||||
"mallocs": 15908623,
|
||||
"numGc": 415,
|
||||
"goroutines": 130,
|
||||
"connections": 128,
|
||||
"accepted": 128
|
||||
},
|
||||
"after": {
|
||||
"heapAlloc": 2816896,
|
||||
"heapInuse": 5300224,
|
||||
"stackInuse": 1048576,
|
||||
"totalAlloc": 1452825560,
|
||||
"mallocs": 15908667,
|
||||
"numGc": 416,
|
||||
"goroutines": 2,
|
||||
"connections": 0,
|
||||
"accepted": 128
|
||||
},
|
||||
"afterReclaim": {
|
||||
"heapAlloc": 1717496,
|
||||
"heapInuse": 3710976,
|
||||
"stackInuse": 1015808,
|
||||
"totalAlloc": 1452826464,
|
||||
"mallocs": 15908673,
|
||||
"numGc": 417,
|
||||
"goroutines": 2,
|
||||
"connections": 0,
|
||||
"accepted": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"adapter": "native",
|
||||
"scenario": "traffic",
|
||||
"concurrency": 128,
|
||||
"run": 1,
|
||||
"requests": 299953,
|
||||
"errors": 0,
|
||||
"elapsedSeconds": 3.003243168,
|
||||
"requestsPerSecond": 99876.36139359062,
|
||||
"p50Millis": 0.622592,
|
||||
"p95Millis": 2.752512,
|
||||
"p99Millis": 32.505856,
|
||||
"serverBytesPerRequest": 4817.3341823552355,
|
||||
"serverAllocsPerRequest": 61.15272726060416,
|
||||
"sampledPeakHeapAlloc": 5668056,
|
||||
"before": {
|
||||
"heapAlloc": 2118392,
|
||||
"heapInuse": 4661248,
|
||||
"stackInuse": 1605632,
|
||||
"totalAlloc": 6143952,
|
||||
"mallocs": 56351,
|
||||
"numGc": 4,
|
||||
"goroutines": 61,
|
||||
"connections": 58,
|
||||
"accepted": 58
|
||||
},
|
||||
"during": {
|
||||
"heapAlloc": 3375320,
|
||||
"heapInuse": 5996544,
|
||||
"stackInuse": 1802240,
|
||||
"totalAlloc": 1451117792,
|
||||
"mallocs": 18399295,
|
||||
"numGc": 528,
|
||||
"goroutines": 131,
|
||||
"connections": 128,
|
||||
"accepted": 128
|
||||
},
|
||||
"after": {
|
||||
"heapAlloc": 2766336,
|
||||
"heapInuse": 5382144,
|
||||
"stackInuse": 1769472,
|
||||
"totalAlloc": 1451125632,
|
||||
"mallocs": 18399341,
|
||||
"numGc": 529,
|
||||
"goroutines": 3,
|
||||
"connections": 0,
|
||||
"accepted": 128
|
||||
},
|
||||
"afterReclaim": {
|
||||
"heapAlloc": 1658104,
|
||||
"heapInuse": 3588096,
|
||||
"stackInuse": 1769472,
|
||||
"totalAlloc": 1451126280,
|
||||
"mallocs": 18399346,
|
||||
"numGc": 530,
|
||||
"goroutines": 3,
|
||||
"connections": 0,
|
||||
"accepted": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"adapter": "nethttp",
|
||||
"scenario": "idle",
|
||||
"concurrency": 128,
|
||||
"run": 1,
|
||||
"errors": 0,
|
||||
"idleHeapDelta": 1838600,
|
||||
"idleHeapPerConnection": 14364.0625,
|
||||
"before": {
|
||||
"heapAlloc": 1521656,
|
||||
"heapInuse": 3260416,
|
||||
"stackInuse": 458752,
|
||||
"totalAlloc": 3029904,
|
||||
"mallocs": 23674,
|
||||
"numGc": 1,
|
||||
"goroutines": 2,
|
||||
"connections": 0,
|
||||
"accepted": 0
|
||||
},
|
||||
"during": {
|
||||
"heapAlloc": 3360256,
|
||||
"heapInuse": 5718016,
|
||||
"stackInuse": 1540096,
|
||||
"totalAlloc": 9686296,
|
||||
"mallocs": 86122,
|
||||
"numGc": 5,
|
||||
"goroutines": 130,
|
||||
"connections": 128,
|
||||
"accepted": 128
|
||||
},
|
||||
"after": {
|
||||
"heapAlloc": 2682728,
|
||||
"heapInuse": 4792320,
|
||||
"stackInuse": 425984,
|
||||
"totalAlloc": 9695376,
|
||||
"mallocs": 86176,
|
||||
"numGc": 6,
|
||||
"goroutines": 2,
|
||||
"connections": 0,
|
||||
"accepted": 128
|
||||
},
|
||||
"afterReclaim": {
|
||||
"heapAlloc": 1604552,
|
||||
"heapInuse": 3440640,
|
||||
"stackInuse": 425984,
|
||||
"totalAlloc": 9696584,
|
||||
"mallocs": 86186,
|
||||
"numGc": 7,
|
||||
"goroutines": 2,
|
||||
"connections": 0,
|
||||
"accepted": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"adapter": "native",
|
||||
"scenario": "idle",
|
||||
"concurrency": 128,
|
||||
"run": 1,
|
||||
"errors": 0,
|
||||
"idleHeapDelta": 1191856,
|
||||
"idleHeapPerConnection": 9311.375,
|
||||
"before": {
|
||||
"heapAlloc": 1521040,
|
||||
"heapInuse": 3325952,
|
||||
"stackInuse": 458752,
|
||||
"totalAlloc": 3029464,
|
||||
"mallocs": 23663,
|
||||
"numGc": 1,
|
||||
"goroutines": 3,
|
||||
"connections": 0,
|
||||
"accepted": 0
|
||||
},
|
||||
"during": {
|
||||
"heapAlloc": 2712896,
|
||||
"heapInuse": 4939776,
|
||||
"stackInuse": 2555904,
|
||||
"totalAlloc": 9083760,
|
||||
"mallocs": 85842,
|
||||
"numGc": 5,
|
||||
"goroutines": 131,
|
||||
"connections": 128,
|
||||
"accepted": 128
|
||||
},
|
||||
"after": {
|
||||
"heapAlloc": 2711312,
|
||||
"heapInuse": 4907008,
|
||||
"stackInuse": 425984,
|
||||
"totalAlloc": 9091576,
|
||||
"mallocs": 85898,
|
||||
"numGc": 6,
|
||||
"goroutines": 3,
|
||||
"connections": 0,
|
||||
"accepted": 128
|
||||
},
|
||||
"afterReclaim": {
|
||||
"heapAlloc": 1608416,
|
||||
"heapInuse": 3416064,
|
||||
"stackInuse": 425984,
|
||||
"totalAlloc": 9092784,
|
||||
"mallocs": 85908,
|
||||
"numGc": 7,
|
||||
"goroutines": 3,
|
||||
"connections": 0,
|
||||
"accepted": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"adapter": "nethttp",
|
||||
"scenario": "idle",
|
||||
"concurrency": 512,
|
||||
"run": 1,
|
||||
"errors": 0,
|
||||
"idleHeapDelta": 7269176,
|
||||
"idleHeapPerConnection": 14197.609375,
|
||||
"before": {
|
||||
"heapAlloc": 1521080,
|
||||
"heapInuse": 3383296,
|
||||
"stackInuse": 458752,
|
||||
"totalAlloc": 3029480,
|
||||
"mallocs": 23669,
|
||||
"numGc": 1,
|
||||
"goroutines": 2,
|
||||
"connections": 0,
|
||||
"accepted": 0
|
||||
},
|
||||
"during": {
|
||||
"heapAlloc": 8790256,
|
||||
"heapInuse": 11960320,
|
||||
"stackInuse": 4718592,
|
||||
"totalAlloc": 29547624,
|
||||
"mallocs": 272853,
|
||||
"numGc": 9,
|
||||
"goroutines": 514,
|
||||
"connections": 512,
|
||||
"accepted": 512
|
||||
},
|
||||
"after": {
|
||||
"heapAlloc": 6121872,
|
||||
"heapInuse": 8749056,
|
||||
"stackInuse": 458752,
|
||||
"totalAlloc": 29580224,
|
||||
"mallocs": 272941,
|
||||
"numGc": 10,
|
||||
"goroutines": 2,
|
||||
"connections": 0,
|
||||
"accepted": 512
|
||||
},
|
||||
"afterReclaim": {
|
||||
"heapAlloc": 1812232,
|
||||
"heapInuse": 3817472,
|
||||
"stackInuse": 458752,
|
||||
"totalAlloc": 29581432,
|
||||
"mallocs": 272951,
|
||||
"numGc": 11,
|
||||
"goroutines": 2,
|
||||
"connections": 0,
|
||||
"accepted": 512
|
||||
}
|
||||
},
|
||||
{
|
||||
"adapter": "native",
|
||||
"scenario": "idle",
|
||||
"concurrency": 512,
|
||||
"run": 1,
|
||||
"errors": 0,
|
||||
"idleHeapDelta": 4687096,
|
||||
"idleHeapPerConnection": 9154.484375,
|
||||
"before": {
|
||||
"heapAlloc": 1520480,
|
||||
"heapInuse": 3293184,
|
||||
"stackInuse": 458752,
|
||||
"totalAlloc": 3028752,
|
||||
"mallocs": 23658,
|
||||
"numGc": 1,
|
||||
"goroutines": 3,
|
||||
"connections": 0,
|
||||
"accepted": 0
|
||||
},
|
||||
"during": {
|
||||
"heapAlloc": 6207576,
|
||||
"heapInuse": 9035776,
|
||||
"stackInuse": 8880128,
|
||||
"totalAlloc": 27129544,
|
||||
"mallocs": 271820,
|
||||
"numGc": 9,
|
||||
"goroutines": 515,
|
||||
"connections": 512,
|
||||
"accepted": 512
|
||||
},
|
||||
"after": {
|
||||
"heapAlloc": 6228280,
|
||||
"heapInuse": 9027584,
|
||||
"stackInuse": 491520,
|
||||
"totalAlloc": 27168240,
|
||||
"mallocs": 271921,
|
||||
"numGc": 10,
|
||||
"goroutines": 3,
|
||||
"connections": 0,
|
||||
"accepted": 512
|
||||
},
|
||||
"afterReclaim": {
|
||||
"heapAlloc": 1812240,
|
||||
"heapInuse": 3645440,
|
||||
"stackInuse": 491520,
|
||||
"totalAlloc": 27169448,
|
||||
"mallocs": 271931,
|
||||
"numGc": 11,
|
||||
"goroutines": 3,
|
||||
"connections": 0,
|
||||
"accepted": 512
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -48,7 +48,7 @@ if err := application.RunWith(ctx, server, ":8443"); err != nil {
|
||||
}
|
||||
```
|
||||
|
||||
需要自己持有 listener 或配置证书文件时,分别使用 `ServeTLS` 或 `RunTLS`;TLS 握手仍受 native 的读超时、连接上限和优雅关闭控制。
|
||||
需要自己持有 listener 或配置证书文件时,分别使用 `ServeTLS` 或 `RunTLS`;TLS 握手仍受 native 的读超时、连接上限和优雅关闭控制,Handler 可通过 `Request.TLS` 读取标准 `tls.ConnectionState`。
|
||||
|
||||
## 可移植路由规则(v0.3.0)
|
||||
|
||||
|
||||
@@ -614,6 +614,10 @@ func readRequest(reader *bufio.Reader, conn net.Conn, maxHeaderBytes int, maxBod
|
||||
RemoteAddr: conn.RemoteAddr().String(),
|
||||
Trailer: trailer,
|
||||
}
|
||||
if tlsConn, ok := conn.(*tls.Conn); ok {
|
||||
state := tlsConn.ConnectionState()
|
||||
request.TLS = &state
|
||||
}
|
||||
if chunked {
|
||||
request.TransferEncoding = []string{"chunked"}
|
||||
}
|
||||
|
||||
@@ -903,36 +903,6 @@ func TestAppRunWithNativeTLS(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestNativeTLSSlowHandshakeTimesOut(t *testing.T) {
|
||||
application := omni.NewWithRouter(netrouter.New())
|
||||
application.GET("/health", func(ctx *omni.Context) error { return ctx.OK("ok") })
|
||||
server := native.New(application)
|
||||
server.ReadHeaderTimeout = 30 * time.Millisecond
|
||||
listener, err := net.Listen("tcp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
certificate := testCertificate(t)
|
||||
done := make(chan error, 1)
|
||||
go func() {
|
||||
done <- server.ServeTLS(context.Background(), listener, &tls.Config{Certificates: []tls.Certificate{certificate}})
|
||||
}()
|
||||
waitForServer(t, listener.Addr().String())
|
||||
defer stopServer(t, server, listener, done)
|
||||
|
||||
conn, err := net.Dial("tcp", listener.Addr().String())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer conn.Close()
|
||||
if err := conn.SetReadDeadline(time.Now().Add(time.Second)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := conn.Read(make([]byte, 1)); err == nil {
|
||||
t.Fatal("slow TLS handshake was not closed")
|
||||
}
|
||||
}
|
||||
|
||||
func testCertificate(t *testing.T) tls.Certificate {
|
||||
t.Helper()
|
||||
key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
|
||||
188
transport/native/tls_test.go
Normal file
188
transport/native/tls_test.go
Normal file
@@ -0,0 +1,188 @@
|
||||
package native_test
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"git.yuntuo.hk/k2safe/go-omni/transport/native"
|
||||
)
|
||||
|
||||
func startNativeTLS(t *testing.T, server *native.Server) (string, *tls.Config) {
|
||||
t.Helper()
|
||||
certificate := testCertificate(t)
|
||||
leaf, err := x509.ParseCertificate(certificate.Certificate[0])
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
roots := x509.NewCertPool()
|
||||
roots.AddCert(leaf)
|
||||
listener, err := net.Listen("tcp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
done := make(chan error, 1)
|
||||
go func() {
|
||||
done <- server.ServeTLS(context.Background(), listener, &tls.Config{
|
||||
Certificates: []tls.Certificate{certificate}, MinVersion: tls.VersionTLS12,
|
||||
NextProtos: []string{"http/1.1"},
|
||||
})
|
||||
}()
|
||||
t.Cleanup(func() {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
|
||||
defer cancel()
|
||||
if err := server.Shutdown(ctx); err != nil {
|
||||
t.Errorf("TLS shutdown: %v", err)
|
||||
}
|
||||
select {
|
||||
case err := <-done:
|
||||
if err != nil {
|
||||
t.Errorf("TLS serve: %v", err)
|
||||
}
|
||||
case <-ctx.Done():
|
||||
t.Error("TLS serve did not exit")
|
||||
}
|
||||
})
|
||||
return listener.Addr().String(), &tls.Config{
|
||||
RootCAs: roots, ServerName: "localhost", MinVersion: tls.VersionTLS12,
|
||||
NextProtos: []string{"http/1.1"},
|
||||
}
|
||||
}
|
||||
|
||||
func requirePeerClose(t *testing.T, conn net.Conn) {
|
||||
t.Helper()
|
||||
conn.SetReadDeadline(time.Now().Add(2 * time.Second))
|
||||
_, err := conn.Read(make([]byte, 1))
|
||||
if err == nil {
|
||||
t.Fatal("expected server to close the connection")
|
||||
}
|
||||
var netErr net.Error
|
||||
if errors.As(err, &netErr) && netErr.Timeout() {
|
||||
t.Fatalf("client timed out; server did not close the connection: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNativeTLSSlowHandshakeTimesOut(t *testing.T) {
|
||||
for _, prefix := range []string{"", "\x16\x03\x01\x00\x64\x01"} {
|
||||
t.Run(fmt.Sprintf("partialBytes=%d", len(prefix)), func(t *testing.T) {
|
||||
var calls atomic.Int32
|
||||
server := native.New(http.HandlerFunc(func(http.ResponseWriter, *http.Request) { calls.Add(1) }))
|
||||
server.ReadHeaderTimeout = 50 * time.Millisecond
|
||||
address, _ := startNativeTLS(t, server)
|
||||
conn, err := net.DialTimeout("tcp", address, time.Second)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer conn.Close()
|
||||
if _, err := io.WriteString(conn, prefix); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
requirePeerClose(t, conn)
|
||||
if calls.Load() != 0 {
|
||||
t.Fatal("unfinished TLS handshake reached the handler")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestNativeTLSConnectionLimitAndKeepAlive(t *testing.T) {
|
||||
var calls atomic.Int32
|
||||
server := native.New(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
calls.Add(1)
|
||||
_, _ = io.WriteString(w, "healthy")
|
||||
}))
|
||||
server.MaxConnections = 1
|
||||
address, config := startNativeTLS(t, server)
|
||||
dial := func() (*tls.Conn, error) {
|
||||
return tls.DialWithDialer(&net.Dialer{Timeout: time.Second}, "tcp", address, config)
|
||||
}
|
||||
first, err := dial()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer first.Close()
|
||||
first.SetDeadline(time.Now().Add(3 * time.Second))
|
||||
reader := bufio.NewReader(first)
|
||||
for index := 0; index < 3; index++ {
|
||||
if _, err := io.WriteString(first, "GET /health HTTP/1.1\r\nHost: localhost\r\n\r\n"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
response, err := http.ReadResponse(reader, &http.Request{Method: http.MethodGet})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
body, err := io.ReadAll(response.Body)
|
||||
response.Body.Close()
|
||||
if err != nil || string(body) != "healthy" || response.Close {
|
||||
t.Fatalf("Keep-Alive response body=%q err=%v close=%v", body, err, response.Close)
|
||||
}
|
||||
}
|
||||
// A completed TLS handshake proves the first slot is held before testing
|
||||
// rejection. TCP accept can still succeed; the TLS handshake must fail.
|
||||
rejected, err := dial()
|
||||
if err == nil {
|
||||
rejected.Close()
|
||||
t.Fatal("TLS connection exceeded MaxConnections")
|
||||
}
|
||||
var netErr net.Error
|
||||
if errors.As(err, &netErr) && netErr.Timeout() {
|
||||
t.Fatalf("over-limit handshake hung: %v", err)
|
||||
}
|
||||
first.Close()
|
||||
deadline := time.Now().Add(2 * time.Second)
|
||||
var next *tls.Conn
|
||||
for time.Now().Before(deadline) {
|
||||
next, err = dial()
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
time.Sleep(time.Millisecond)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("TLS connection capacity not released: %v", err)
|
||||
}
|
||||
defer next.Close()
|
||||
next.SetDeadline(time.Now().Add(time.Second))
|
||||
if _, err := io.WriteString(next, "GET /health HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
response, err := http.ReadResponse(bufio.NewReader(next), &http.Request{Method: http.MethodGet})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
body, err := io.ReadAll(response.Body)
|
||||
response.Body.Close()
|
||||
if err != nil || string(body) != "healthy" || calls.Load() != 4 {
|
||||
t.Fatalf("recovered response=%q calls=%d err=%v", body, calls.Load(), err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNativeTLSRequestMetadata(t *testing.T) {
|
||||
server := native.New(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.TLS == nil || !r.TLS.HandshakeComplete || r.TLS.NegotiatedProtocol != "http/1.1" {
|
||||
http.Error(w, "missing TLS request metadata", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
}))
|
||||
address, config := startNativeTLS(t, server)
|
||||
client := &http.Client{Transport: &http.Transport{TLSClientConfig: config}, Timeout: 2 * time.Second}
|
||||
defer client.CloseIdleConnections()
|
||||
response, err := client.Get("https://" + address + "/")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer response.Body.Close()
|
||||
if response.StatusCode != http.StatusNoContent {
|
||||
t.Fatalf("TLS metadata unavailable to handler: status=%d", response.StatusCode)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user