必须显式配置readtimeout、writetimeout和idletimeout三类超时,分别控制读请求、写响应和keep-alive空闲时长,避免goroutine堆积与连接泄漏。

http.Server 必须显式设超时和连接限制
默认的 http.Server 没有超时,一个慢请求就能卡死整个服务。不配就等于裸奔。
-
ReadTimeout控制从 Accept 到读完 request body 的总时长,建议 3–5 秒;客户端发一半就断连时,它能及时释放 goroutine -
WriteTimeout从WriteHeader开始计时,防 handler 内部阻塞(比如 DB 查询卡住),建议比业务预期最大耗时多留 2 秒 -
IdleTimeout管 keep-alive 连接空闲时间,设 30 秒可避免 TIME_WAIT 堆积;太短会频繁重连,太长则浪费 fd - 不设
MaxConns?靠http_server_open_connections指标 +ulimit -n反推,别硬写死
别在 handler 里直接 go fn(),用带限流的 worker pool
裸起 goroutine 是高并发 API 泄漏和 OOM 的头号原因:没上下文取消、没并发数控制、panic 不 recover、资源不复用。
- 用
golang.org/x/sync/semaphore的semaphore.NewWeighted(100),比自己写 channel 控制更稳 - 所有异步任务必须接收
context.Context,且 handler 返回前调用cancel() - 别在
http.HandlerFunc里defer recover()—— 它捕不到 goroutine 里的 panic;recover 要包在 worker 函数体最外层 - 日志打点必须带 trace ID,否则并发下根本分不清哪条日志属于哪个请求
高频 JSON 序列化别碰 json.Marshal
QPS 上万时,json.Marshal 的反射开销会在 CPU 火焰图里扎眼地冒出来,reflect.Value.Interface 占比飙升。
- 对固定结构体(如
User、Order),用easyjson或ffjson生成静态 marshal/unmarshal 方法 - 避免
json:",omitempty"配合指针字段——每次判断是否为nil的开销被严重低估 - 响应体简单固定(如
{"code":0,"msg":"ok"}),直接拼[]byte或用sync.Pool复用bytes.Buffer - 绝对不用
map[string]interface{}做通用响应体,类型擦除 + 反射双重惩罚
中间件和 request body 读取要格外小心
想记录请求日志或做鉴权,一不小心就读光了 body,下游 handler 再读就返回空。
- 别用
io.ReadAll或bytes.Buffer直接读r.Body;改用r.Body = http.MaxBytesReader(nil, r.Body, maxBodySize)加保护 - 真要复用 body,得先
io.Copy到bytes.Buffer,再用io.NopCloser包一层塞回r.Body - gin 框架里用
c.ShouldBindJSON前,确保没其他中间件提前消费过 body;否则要手动c.Request.Body = io.NopCloser(bytes.NewBuffer(buf)) - gzip/deflate 压缩用
restful.NewBoundedCachedCompressors(50, 30),避免无界缓存导致内存泄漏
pprof 里常被忽略的是 runtime.mallocgc 和 net/http.serverHandler.ServeHTTP 的调用栈深度——这两处暴增,往往意味着 JSON 反射或中间件嵌套失控。大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!











