fasthttp本身不支持优雅重启,需自行实现信号监听、子进程接管和连接计数,且Server所有超时与并发参数必须显式调优:IdleTimeout=60s、Read/WriteTimeout=30s、Concurrency=256×NumCPU、MaxConnsPerIP=0;Client端须设MaxIdleConnDuration=30s并按host隔离实例,否则压测即超时。

直接说结论:fasthttp 本身不支持优雅重启,必须自己实现信号监听 + 子进程接管 + 连接计数,且所有 fasthttp.Server 配置项(尤其是超时和并发)必须显式调优,否则一压就挂。
fasthttp.Server 默认配置为什么一压就超时
默认 IdleTimeout 只有 10 秒,ReadTimeout 和 WriteTimeout 是 0(即无限),但实际压测中你会看到大量 timeout: timed out waiting for idle connection。这不是后端慢,是客户端连接池被快速耗尽又不敢复用——因为服务端空闲连接太短,刚建好就被关了。
-
Server.IdleTimeout = 60 * time.Second(必须设,别信默认) -
Server.ReadTimeout = 30 * time.Second、Server.WriteTimeout = 30 * time.Second(防长连接卡死) -
Server.Concurrency = 256 * runtime.NumCPU()(避免 goroutine 调度瓶颈) -
Server.MaxConnsPerIP = 0(不限制单 IP 连接数,按需放开)
如何安全地 fork 新进程并复用监听 socket
Go 标准库的 net.Listener 不支持跨进程传递 fd,但 fasthttp.Server 支持传入已存在的 listener。关键不是“怎么 fork”,而是“怎么把 fd 交给子进程”:
- 主进程收到
SIGUSR2后,调用listener.File()获取底层*os.File - 用
syscall.Exec启动新进程,并通过env或argv把fd编号传进去(如LISTEN_FD=3) - 新进程启动时检查环境变量,用
os.NewFile(uintptr(fdNum), "")恢复 listener - 老进程在
srv.Shutdown()前要先关闭 accept(listener.Close()),但保持已建立连接继续处理
注意:fasthttp.Server 没有内置 Shutdown() 方法,得自己封装:用 sync.WaitGroup 计数活跃请求,在信号到来时停止 Accept(),等 wg 归零再退出。
goroutine 里读 PostBody() 为什么总出错
因为 ctx.PostBody() 返回的是内部缓冲区切片视图,不是拷贝。一旦你把它扔进 goroutine 异步处理,下一请求进来就会覆盖那块内存——结果不是空数据就是 panic。
- 错误写法:
go process(ctx.PostBody()) - 正确写法:
body := append([]byte(nil), ctx.PostBody()),立刻复制 - 同理适用于:
ctx.FormValue("x")、ctx.QueryArgs().Peek("y")、ctx.Request.Header.Peek("User-Agent") - 高频小 body 场景可配
sync.Pool管理[]byte,但别池化 >4KB 的 slice,GC 反而更重
client 端复用连接池失败的真实原因
fasthttp.Client 默认 MaxIdleConnDuration = 1 * time.Second,比 net/http.Transport 的默认值(30 秒)激进得多。线上并发稍高,连接池瞬间打满,新请求只能等或 timeout。
- 必须显式设置:
client.MaxIdleConnDuration = 30 * time.Second - 调多个后端域名时,不要共用一个 client 实例——不同 host 的连接池会争抢
- 别设成 5 分钟以上:
MaxIdleConnDuration过长会导致 fd 长期占用,系统级文件描述符容易耗尽 - 如果后端支持 HTTP/2,
fasthttp默认不处理 h2 帧,得自己配http2.ConfigureServer,且仍需手动管理 TLS 连接
最易被忽略的一点:所有基于 fd 复用的优雅重启逻辑,都依赖于 listener 的生命周期管理是否干净——os.File 忘记 Close(),子进程拿到的就是无效 fd;WaitGroup 计数漏减一次,老进程就永远 hang 在 shutdown 等待里。


















