什么时候要自己维护一个 ClientConn 池?池开多大?怎么选连接?预热有用吗?一条连接对服务端有多贵?这篇用服务端放在另一个进程的方式量出这些数字。
1 条连接: 8152 请求/秒(理论上限 10000);p50 36418 µs、p99 200046 µs 2 条连接: 16577 请求/秒(理论上限 20000);p50 22859 µs、p99 71192 µs 4 条连接: 34221 请求/秒(理论上限 40000);p50 11490 µs、p99 14944 µs 8 条连接: 34243 请求/秒(理论上限 80000);p50 11476 µs、p99 14638 µs
一条连接同时能跑的流有上限(服务端的 MaxConcurrentStreams)。并发超过它,或者单连接的 CPU/带宽成了瓶颈,才需要多条连接。上限约等于连接数 × 每连接并发上限 ÷ 处理时间。
轮流 1150 请求/秒;p50 1692 µs、p99 226370 µs 随机 1198 请求/秒;p50 2705 µs、p99 221361 µs 在途最少 1437 请求/秒;p50 6531 µs、p99 217064 µs
轮流、随机、在途最少三种策略会让吞吐与延迟分布不同。在途最少让名额利用更均匀,吞吐更高,但不是所有指标都更好。
没有预热 200 个并发调用:p50 4172 µs、p99 7036 µs、最慢 7671 µs;总耗时 7.8 ms Connect() 并等 200 ms 200 个并发调用:p50 5443 µs、p99 6388 µs、最慢 6822 µs;总耗时 7.2 ms
NewClient 是惰性的。本机回环上预热看不出收益;在真实网络、尤其有 TLS 握手时才可能有明显差别,需要实测。
基线 2 个 goroutine;1000 条空闲连接后 3002 个(每条连接 +3.0);堆 +38.4 KiB/条;goroutine 栈 +9.2 KiB/条 关闭这 1000 条连接之后:2 个 goroutine
服务端每条连接都有读写 goroutine 和缓冲,实测每条空闲连接约 48 KiB。池不要开得比需要的大。