Go HTTP服务在并发较高或长时间运行后,经常会遇到Too Many Open Files的错误,导致新的请求无法建立连接,服务可用性下降。该错误的根本原因是进程打开的文件描述符超过了系统限制,而在Linux中,每一个TCP连接、文件、管道都对应一个文件描述符。

常见导致该错误的原因
- HTTP客户端或服务端未正确关闭
response.Body,连接一直占用 - 大量短连接产生TIME_WAIT,文件描述符未及时回收
- 系统ulimit设置过低,默认往往只有1024
- 未设置连接超时和空闲连接回收策略
代码层面如何处理
正确关闭响应体
使用http.Get或client.Do时,必须调用resp.Body.Close(),否则底层连接不会归还到连接池。
package main
import (
"io"
"net/http"
)
func fetch(url string) error {
resp, err := http.Get(url)
if err != nil {
return err
}
// 必须关闭Body,即使不读取内容
defer resp.Body.Close()
_, err = io.Copy(io.Discard, resp.Body)
return err
}
配置HTTP客户端超时
避免连接无限等待,应设置超时和空闲连接回收参数。
package main
import (
"net/http"
"time"
)
func newClient() *http.Client {
return &http.Client{
Timeout: 10 * time.Second,
Transport: &http.Transport{
MaxIdleConns: 100,
MaxIdleConnsPerHost: 10,
IdleConnTimeout: 30 * time.Second,
},
}
}
服务端配置建议
如果是被调用方,可设置http.Server的读写超时,防止慢连接长期占用。
package main
import (
"net/http"
"time"
)
func main() {
srv := &http.Server{
Addr: ":8080",
ReadTimeout: 5 * time.Second,
WriteTimeout: 10 * time.Second,
}
srv.ListenAndServe()
}
系统层面调整
通过命令查看当前限制并修改。
# 查看当前进程限制 ulimit -n # 临时修改 ulimit -n 65535 # 永久修改可编辑 /etc/security/limits.conf # * soft nofile 65535 # * hard nofile 65535
总结
处理Too Many Open Files需要从代码规范、客户端服务端参数、系统限制三方面入手。养成关闭Body的习惯,配置合理的超时与连接池,再把系统文件描述符上限调高,基本可以彻底解决该问题。
GoHTTP服务too_many_open_files修改时间:2026-07-29 08:00:08