英文:
Go net/http server error: accept tcp [::]:443: accept4: too many open files; retrying
问题
这是我的服务器代码:
package main
import (
"my-project/pkg/configuration"
"my-project/pkg/logger"
"my-project/pkg/server/appConfig"
"my-project/pkg/server/handlers"
"net/http"
"os"
"strings"
)
func main() {
if len(os.Args) < 2 {
logger.Log("error", "main", "Missing config.json file path as argument")
return
}
configuration := configuration.Configuration{}
appConfig.InitConfig(os.Args[1], &configuration)
// 下载文件
http.HandleFunc("/file-download", handlers.DownloadFile(&configuration))
// 上传文件
http.HandleFunc("/file-upload", handlers.UploadFile(&configuration))
// 获取URL
http.HandleFunc("/file-url", handlers.GetUrl(&configuration))
// 删除
http.HandleFunc("/delete", handlers.DeleteHandler(&configuration))
// 文件系统
fs := http.FileServer(http.Dir(configuration.RootStoragePath))
corsFS := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if strings.HasSuffix(r.URL.Path, "/") {
http.NotFound(w, r)
return
}
w.Header().Add("Access-Control-Allow-Origin", "*")
fs.ServeHTTP(w, r)
})
http.Handle("/", corsFS)
err := http.ListenAndServeTLS(":443", "crt/server.crt", "crt/server.key", nil)
if err != nil {
logger.Log("error", "ListenAndServeTLS", err.Error())
}
}
服务器处于中等负载状态。
服务器在运行一天后崩溃,我得到了以下错误:
http: Accept error: accept tcp [::]:443: accept4: too many open files; retrying
命令:
ls -ltr /proc/{PROCESS_ID}/fd
文件和套接字的列表 [XXXXXX] 不断增长。
我不想更改 ulimit(1024),我不认为这是一个长期的解决方案...
我真的不知道问题可能出在哪里... 在处理程序中,我操作文件,但我确保使用 defer Close()...
我需要设置超时吗?如果需要,在哪里设置?
非常感谢您提供的帮助...
英文:
Here is my server :
package main
import (
"my-project/pkg/configuration"
"my-project/pkg/logger"
"my-project/pkg/server/appConfig"
"my-project/pkg/server/handlers"
"net/http"
"os"
"strings"
)
func main() {
if len(os.Args) < 2 {
logger.Log("error", "main", "Missing config.json file path as argument")
return
}
configuration := configuration.Configuration{}
appConfig.InitConfig(os.Args[1], &configuration)
// download file
http.HandleFunc("/file-download", handlers.DownloadFile(&configuration))
// upload file
http.HandleFunc("/file-upload", handlers.UploadFile(&configuration))
// Get url
http.HandleFunc("/file-url", handlers.GetUrl(&configuration))
// Delete
http.HandleFunc("/delete", handlers.DeleteHandler(&configuration))
// file system
fs := http.FileServer(http.Dir(configuration.RootStoragePath))
corsFS := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if strings.HasSuffix(r.URL.Path, "/") {
http.NotFound(w, r)
return
}
w.Header().Add("Access-Control-Allow-Origin", "*")
fs.ServeHTTP(w, r)
})
http.Handle("/", corsFS)
err := http.ListenAndServeTLS(":443", "crt/server.crt", "crt/server.key", nil)
if err != nil {
logger.Log("error", "ListenAndServeTLS", err.Error())
}
}
The server is under medium load.
The server crashed after a day of running,
I got the following error:
http: Accept error: accept tcp [::]:443: accept4: too many open files; retrying
The command :
ls -ltr /proc/{PROCESS_ID}/fd
And the list of file, and socket:[XXXXXX] is growing all the time.
I don't want to change ulimit (1024), I don't think it is a long terme fix...
I don't really see where the problem could come from... In the handlers, I manipulate files but I take care to do defer Close()...
Do I have to set timeouts? If so where?
Thank you in advance for all the help ...
答案1
得分: 1
我终于成功找到了一个解决方案。
事实上,net/http
包的 http.ListenAndServe
方法默认没有超时设置。这是 Go 团队的自愿选择。因此,在生产环境中,需要声明一个 http.Server{}
并进行配置。Go 文档。来源:Cloudflare 博客文章
srv := &http.Server{
Addr: ":443",
ReadTimeout: 30 * time.Second,
WriteTimeout: 120 * time.Second,
}
srv.SetKeepAlivesEnabled(false)
err := srv.ListenAndServeTLS("crt/server.crt", "crt/server.key")
http.DefaultServeMux
是默认的请求多路复用器,HandleFunc
在 DefaultServeMux
中注册给定模式的处理函数。
以下是实现代码:
func main() {
if len(os.Args) < 2 {
logger.Log("error", "main", "Missing config.json file path as argument")
return
}
configuration := configuration.Configuration{}
appConfig.InitConfig(os.Args[1], &configuration)
// 下载文件
http.HandleFunc("/file-download", handlers.DownloadFile(&configuration))
// 上传文件
http.HandleFunc("/file-upload", handlers.UploadFile(&configuration))
// 获取 URL
http.HandleFunc("/file-url", handlers.GetUrl(&configuration))
// 删除
http.HandleFunc("/delete", handlers.DeleteHandler(&configuration))
// 文件系统
fs := http.FileServer(http.Dir(configuration.RootStoragePath))
corsFS := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if strings.HasSuffix(r.URL.Path, "/") {
http.NotFound(w, r)
return
}
w.Header().Add("Access-Control-Allow-Origin", "*")
fs.ServeHTTP(w, r)
})
http.Handle("/", corsFS)
srv := &http.Server{
Addr: ":443",
ReadTimeout: 30 * time.Second,
WriteTimeout: 120 * time.Second,
}
srv.SetKeepAlivesEnabled(false)
err := srv.ListenAndServeTLS("crt/server.crt", "crt/server.key")
if err != nil {
logger.Log("error", "ListenAndServeTLS", err.Error())
os.Exit(1)
}
}
如果你有其他建议,我当然感兴趣。
英文:
I finally managed to find a solution.
The fact is that the http.ListenAndServe
method of the net/http
package has no timeout by default. This is voluntary from the Go team. So for a service in production, it is necessary to declare a http.Server{}
and to configure it. Go doc.
Source : Cloudflare blog post
srv := &http.Server{
Addr: ":443",
ReadTimeout: 30 * time.Second,
WriteTimeout: 120 * time.Second,
}
srv.SetKeepAlivesEnabled(false)
err := srv.ListenAndServeTLS("crt/server.crt", "crt/server.key")
http.DefaultServeMux
is the default request multiplexer, and HandleFunc
registers the handler function for the given pattern in the DefaultServeMux
.
Here is the implementation :
func main() {
if len(os.Args) < 2 {
logger.Log("error", "main", "Missing config.json file path as argument")
return
}
configuration := configuration.Configuration{}
appConfig.InitConfig(os.Args[1], &configuration)
// download file
http.HandleFunc("/file-download", handlers.DownloadFile(&configuration))
// upload file
http.HandleFunc("/file-upload", handlers.UploadFile(&configuration))
// Get url
http.HandleFunc("/file-url", handlers.GetUrl(&configuration))
// Delete
http.HandleFunc("/delete", handlers.DeleteHandler(&configuration))
// file system
fs := http.FileServer(http.Dir(configuration.RootStoragePath))
corsFS := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if strings.HasSuffix(r.URL.Path, "/") {
http.NotFound(w, r)
return
}
w.Header().Add("Access-Control-Allow-Origin", "*")
fs.ServeHTTP(w, r)
})
http.Handle("/", corsFS)
srv := &http.Server{
Addr: ":443",
ReadTimeout: 30 * time.Second,
WriteTimeout: 120 * time.Second,
}
srv.SetKeepAlivesEnabled(false)
err := srv.ListenAndServeTLS("crt/server.crt", "crt/server.key")
if err != nil {
logger.Log("error", "ListenAndServeTLS", err.Error())
os.Exit(1)
}
}
If you have any other advice, I'm obviously interested.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论