http.server超时必须显式配置,readtimeout(建议5s)控制连接建立到请求头读完,writetimeout(建议10s)控制响应写入完成,idletimeout不作用于handler内慢逻辑;三者缺一不可,否则goroutine泄漏导致资源耗尽。

http.Server 超时设置必须显式配置
默认不设超时,一个慢请求就能卡住整个 goroutine,不是并发高导致的,是资源没释放。ReadTimeout 和 WriteTimeout 必须设,IdleTimeout 不管正在处理的请求。
-
ReadTimeout控制从连接建立到请求头读完的时间,建议5 * time.Second;大文件上传可单独用ReadHeaderTimeout -
WriteTimeout控制响应写入完成时间,建议10 * time.Second,覆盖 DB 写入、日志等潜在阻塞点 - 别只依赖
IdleTimeout——它对已进入 handler 的慢逻辑完全无效
goroutine 泄漏比创建多更危险
问题不在“能不能开”,而在“开完有没有收”。未加限制的 go process(r) 会随流量线性堆积,最终耗尽内存或触发调度雪崩。
- 用带缓冲 channel 当信号量:比如
sem := make(chan struct{}, 100)控制并发上限 - 避免在 handler 里直接起 goroutine 处理 I/O,尤其没带
context.WithTimeout的 DB 查询或 HTTP 调用 - 若必须异步,优先走 worker pool(如
ants),而非每次新建
sync.Pool 不是万能的,但不用一定吃亏
高频小对象(bytes.Buffer、json.Decoder、自定义 Message)复用收益明确;但大对象或生命周期长的对象放进 Pool 反而增加 GC 扫描负担。
- Pool 对象必须在使用后
Put回去,且不能持有外部引用(否则可能造成内存泄漏) - 初始化
New函数要轻量,不能含 I/O 或锁;例如return &MyStruct{}安全,return db.QueryRow(...)危险 - 用
go build -gcflags="-m"看关键变量是否逃逸——栈上分配永远优于 Pool 复用
gRPC 吞吐瓶颈常卡在流控和压缩协商上
HTTP/2 多路复用能力再强,也扛不住服务端不设限、客户端不压缩、连接不复用这三重浪费。
- 服务端必设
grpc.MaxConcurrentStreams(100),否则单连接突发大量 stream 会挤占其他连接资源 - 客户端启用压缩需两端一致:
grpc.WithCompressor(grpc.NewGZIPCompressor()),否则协商失败退为明文 - 务必复用
grpc.ClientConn,每个请求都grpc.Dial是吞吐量杀手,连接建立开销远超序列化
真正卡住吞吐的,往往不是代码写得不够“快”,而是连接没关、goroutine 没收、buffer 没复用、stream 没限——这些点不盯住,压测数据再好看也撑不过真实流量洪峰。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











