应设置 http.Server 的 ReadTimeout 和 WriteTimeout 防止慢连接长期占用资源,建议分别设为 5s 和 10s;禁用 KeepAlive 或限制 MaxIdleConns;handler 中所有 I/O 必须使用带超时的 context;合理使用 sync.Pool 复用对象。

用 http.Server 的 ReadTimeout 和 WriteTimeout 防止连接长期占用
默认情况下,http.Server 没有设置读写超时,一个慢客户端或网络抖动就可能让 goroutine 卡住几十秒甚至更久,迅速耗尽连接池和内存。这不是并发高导致的,而是资源没及时释放。
实操建议:
立即学习“go语言免费学习笔记(深入)”;
-
ReadTimeout控制从 TCP 连接建立到请求头读完的最大时间,建议设为5 * time.Second;若服务需接收大文件上传,可单独用ReadHeaderTimeout控制只读 header 的时间 -
WriteTimeout控制从响应开始写入到完全写完的上限,建议设为10 * time.Second,避免 handler 逻辑卡在日志、DB 写入等环节拖垮整个连接队列 - 不要只设
IdleTimeout—— 它只管空闲连接,对正在处理的慢请求无效
server := &http.Server{
Addr: ":8080",
Handler: myHandler,
ReadTimeout: 5 * time.Second,
WriteTimeout: 10 * time.Second,
IdleTimeout: 30 * time.Second,
}禁用 HTTP/1.1 的 KeepAlive 或合理调小 MaxIdleConns
HTTP/1.1 默认启用长连接,但若后端是短生命周期服务(如 Serverless、K8s Pod 频繁重启),客户端持续复用旧连接会触发 “connection reset” 或 “broken pipe”,反而引发重试风暴。同时,过大的连接池会占用大量文件描述符和内存。
实操建议:
立即学习“go语言免费学习笔记(深入)”;
- 在反向代理(如 Nginx)后部署时,通常应关闭 Go 服务端的
KeepAlive:Server.SetKeepAlivesEnabled(false) - 若必须开启长连接,务必限制连接数:
http.DefaultTransport.MaxIdleConns = 100、MaxIdleConnsPerHost = 100,避免单 host 耗尽 fd - 注意:这些参数作用于
http.Transport(客户端),服务端控制靠http.Server的MaxConns(Go 1.19+)或ConnState回调手动计数
避免在 handler 中做同步阻塞操作
常见错误是把数据库查询、外部 API 调用、JSON 解析、模板渲染全放在主 goroutine 里顺序执行,尤其当 DB 查询未加 context 超时或没走连接池时,一个慢 SQL 就会让整个 handler 卡住,吞吐量断崖下跌。
实操建议:
立即学习“go语言免费学习笔记(深入)”;
- 所有 I/O 操作必须带
context.Context并设超时,例如:db.QueryContext(ctx, query),且ctx应来自req.Context() - 禁止用
time.Sleep、log.Printf(尤其在循环中)、json.Marshal处理超大结构体 —— 这些看似轻量的操作在高并发下会显著拉高 GC 压力和延迟 - 高频小响应优先用
strconv替代fmt.Sprintf,用bytes.Buffer预分配容量写 JSON,而非json.Marshal直出
用 sync.Pool 复用临时对象,但别滥用
高频创建小对象(如 bytes.Buffer、strings.Builder、自定义 request struct)会导致 GC 频繁触发,表现为 CPU 持续 30%+ 且 p99 延迟毛刺明显。但 sync.Pool 不是银弹 —— 错误使用反而增加逃逸和竞争开销。
实操建议:
立即学习“go语言免费学习笔记(深入)”;
- 只池化生命周期明确、大小稳定、构造成本高的对象,例如:
sync.Pool{New: func() interface{} { return new(bytes.Buffer) }} - 每次 Get 后必须清空(
b.Reset()),否则残留数据会污染后续请求 - 不要池化含指针字段或依赖外部状态的对象;也不要池化
context.Context或http.Request—— 它们本就是 per-request 的 - 上线前用
go tool pprof -alloc_space对比启用前后堆分配量,确认真实收益
真正卡吞吐的地方往往不在算法,而在连接管理是否干净、context 是否贯穿到底、临时内存是否失控 —— 这三处调对了,QPS 常能翻倍,而不用动核心业务逻辑。











