Golang:http服务器保持打开的goroutine

huangapple go评论89阅读模式
英文:

Golang: http server leaving open goroutines

问题

我在Go中搭建了一个HTTP服务器,每天有一千多个访问者。现在我遇到了一个累积的Goroutine问题。在一天的过程中,我似乎从HTTP服务器中获得了一千多个新的Goroutine。

我不确定我是如何搞砸处理程序的。

http.Handle("/", http.FileServer(http.Dir(config.htdocs_path)))

下面是堆栈中的一个Goroutine

goroutine 1582 [chan receive]:
net.(*pollServer).WaitRead(0xf84007f680, 0xf84066dea0, 0xf84007aa80, 0xb, 0x1, ...)
        /home/ec2-user/go/src/pkg/net/fd.go:268 +0x73
net.(*netFD).Read(0xf84066dea0, 0xf840ec1000, 0x100000001000, 0x7f7effffffff, 0xf84007c0f0, ...)
        /home/ec2-user/go/src/pkg/net/fd.go:428 +0x1ec
net.(*TCPConn).Read(0xf84068aff8, 0xf840ec1000, 0x100000001000, 0xf800000002, 0x0, ...)
        /home/ec2-user/go/src/pkg/net/tcpsock_posix.go:87 +0xce
io.(*LimitedReader).Read(0xf840d1bc20, 0xf840ec1000, 0x100000001000, 0xdcb00000000, 0x0, ...)
        /home/ec2-user/go/src/pkg/io/io.go:394 +0xc1
bufio.(*Reader).fill(0xf8405b0900, 0xdcb00000000)
        /home/ec2-user/go/src/pkg/bufio/bufio.go:77 +0xf0
bufio.(*Reader).ReadSlice(0xf8405b0900, 0xf840d1bc0a, 0x0, 0x0, 0x0, ...)
        /home/ec2-user/go/src/pkg/bufio/bufio.go:257 +0x1b6
bufio.(*Reader).ReadLine(0xf8405b0900, 0x0, 0x0, 0x0, 0x0, ...)
        /home/ec2-user/go/src/pkg/bufio/bufio.go:283 +0x5b
net/textproto.(*Reader).readLineSlice(0xf840730660, 0xc0, 0x100000000, 0x7f7e00000001)
        /home/ec2-user/go/src/pkg/net/textproto/reader.go:55 +0x4f
net/textproto.(*Reader).ReadLine(0xf840730660, 0xf84061f300, 0x0, 0x48411c)
        /home/ec2-user/go/src/pkg/net/textproto/reader.go:36 +0x25
net/http.ReadRequest(0xf8405b0900, 0xf84061f300, 0x0, 0x0, 0x100000400ccf60, ...)
        /home/ec2-user/go/src/pkg/net/http/request.go:457 +0xb1
net/http.(*conn).readRequest(0xf8402b2b40, 0xf8400e3fc0, 0x0, 0x0, 0xf8405b0a80, ...)
        /home/ec2-user/go/src/pkg/net/http/server.go:240 +0xa8
net/http.(*conn).serve(0xf8402b2b40, 0x0)
        /home/ec2-user/go/src/pkg/net/http/server.go:594 +0x145
created by net/http.(*Server).Serve
        /home/ec2-user/go/src/pkg/net/http/server.go:1040 +0x430

看起来连接在读取状态下被卡住了。就像HTTP服务器没有超时一样。默认服务器没有读取超时吗?

go version go1

英文:

I've put up an http server written in Go and it's getting a little over a thousand visitors a day. I have an accumulating Goroutine problem now. Over the course of a day I seem to get a little over a thousand new Goroutines from the http server.

I'm not sure how I could mess up the handler.

http.Handle("/", http.FileServer(http.Dir(config.htdocs_path)))

Below is one of the goroutines from the stack

goroutine 1582 [chan receive]:
net.(*pollServer).WaitRead(0xf84007f680, 0xf84066dea0, 0xf84007aa80, 0xb, 0x1, ...)
        /home/ec2-user/go/src/pkg/net/fd.go:268 +0x73
net.(*netFD).Read(0xf84066dea0, 0xf840ec1000, 0x100000001000, 0x7f7effffffff, 0xf84007c0f0, ...)
        /home/ec2-user/go/src/pkg/net/fd.go:428 +0x1ec
net.(*TCPConn).Read(0xf84068aff8, 0xf840ec1000, 0x100000001000, 0xf800000002, 0x0, ...)
        /home/ec2-user/go/src/pkg/net/tcpsock_posix.go:87 +0xce
io.(*LimitedReader).Read(0xf840d1bc20, 0xf840ec1000, 0x100000001000, 0xdcb00000000, 0x0, ...)
        /home/ec2-user/go/src/pkg/io/io.go:394 +0xc1
bufio.(*Reader).fill(0xf8405b0900, 0xdcb00000000)
        /home/ec2-user/go/src/pkg/bufio/bufio.go:77 +0xf0
bufio.(*Reader).ReadSlice(0xf8405b0900, 0xf840d1bc0a, 0x0, 0x0, 0x0, ...)
        /home/ec2-user/go/src/pkg/bufio/bufio.go:257 +0x1b6
bufio.(*Reader).ReadLine(0xf8405b0900, 0x0, 0x0, 0x0, 0x0, ...)
        /home/ec2-user/go/src/pkg/bufio/bufio.go:283 +0x5b
net/textproto.(*Reader).readLineSlice(0xf840730660, 0xc0, 0x100000000, 0x7f7e00000001)
        /home/ec2-user/go/src/pkg/net/textproto/reader.go:55 +0x4f
net/textproto.(*Reader).ReadLine(0xf840730660, 0xf84061f300, 0x0, 0x48411c)
        /home/ec2-user/go/src/pkg/net/textproto/reader.go:36 +0x25
net/http.ReadRequest(0xf8405b0900, 0xf84061f300, 0x0, 0x0, 0x100000400ccf60, ...)
        /home/ec2-user/go/src/pkg/net/http/request.go:457 +0xb1
net/http.(*conn).readRequest(0xf8402b2b40, 0xf8400e3fc0, 0x0, 0x0, 0xf8405b0a80, ...)
        /home/ec2-user/go/src/pkg/net/http/server.go:240 +0xa8
net/http.(*conn).serve(0xf8402b2b40, 0x0)
        /home/ec2-user/go/src/pkg/net/http/server.go:594 +0x145
created by net/http.(*Server).Serve
        /home/ec2-user/go/src/pkg/net/http/server.go:1040 +0x430

It seems like connections are getting stuck in the read state. Like the http server isn't timing them out. Does the default server not have a read timeout?

go version go1

答案1

得分: 58

所有这些goroutine都在读取的原因是保持连接。当浏览器发送一个保持连接的头部时,服务器会保持连接以接受更多的请求。当客户端请求许多小文件且TCP连接是重要开销时,这是一件好事。读取超时将确保在请求之间没有保持连接的时间超过一定时间。这将关闭保持连接的连接,但也防止某人上传超过超时时间。不幸的是,目前还没有保持连接特定的超时选项。

默认情况下,没有超时。您可以在Server结构中设置超时http://golang.org/pkg/net/http/#Server

srv := &http.Server{
    Handler: http.FileServer(http.Dir(config.htdocs_path)),
    ReadTimeout: 30*time.Second,
}
srv.ListenAndServe()
英文:

The reason all these goroutines are reading is keep-alive. When a browser sends a keep-alive header, the server keeps the connection open to accept more requests. This is a good thing when the client is requesting many small files and the TCP connection is significant overhead. A read timeout would ensure that no connection was kept alive more than a certain time between requests. This would close keep alive connections but also prevent someone from uploading for longer than the timeout. Unfortunately, there is no keep-alive specific timeout option yet.

By default, there is no timeout. You can set a timeout in the Server struct http://golang.org/pkg/net/http/#Server

srv := &http.Server{
    Handler: http.FileServer(http.Dir(config.htdocs_path)),
    ReadTimeout: 30*time.Second,
}
srv.ListenAndServe()

答案2

得分: 0

在使用HTTP连接时要小心使用ReadTimeout和WriteTimeout。我认为它们不会按照你的期望工作。特别是,它们有可能使连接处于不可用状态,而不是实际关闭连接。请参考https://groups.google.com/forum/#!topic/golang-nuts/oBIh_R7-pJQ了解详细信息,特别是我看到有些情况下,ReadTimeout会使连接不可用,并在HTTP处理程序超过超时时间时导致响应被丢弃。如果将超时时间设置为超过任何处理程序的响应时间的大值,可能会没问题。

英文:

Be careful about using ReadTimeout and WriteTimeout on HTTP connections. I don't think they do what you expect them to. In particular, they have a tendency to leave connections in an unusable state without actually closing them. See https://groups.google.com/forum/#!topic/golang-nuts/oBIh_R7-pJQ for details, in particular, I see cases where a ReadTimeout makes connections unusable and causes responses to be dropped on the floor when the HTTP handler time exceeds the timeout. If you set the timeout to a large value that exceeds the response time of any handler you may be OK.

答案3

得分: 0

Stephen的答案对我只有在与以下内容结合使用时才有效:服务器可以告诉客户端它不希望或不支持保持连接。为此,在提供服务之前设置相应的标志:

server := &http.Server{
  // ... 参见Stephen的答案
}
server.SetKeepAlivesEnabled(false)
server.ListenAndServe()

这将设置响应头Connection: close,并且大多数客户端将从他们的一侧终止连接。

英文:

Stephen's answer worked for me only in combination with the following: the server can tell its clients that it does not wish or support to keep connections open. To do so, set the according flag before serving:

server := &http.Server{
  // ... see Stephen's answer
}
server.SetKeepAlivesEnabled(false)
server.ListenAndServe()

This will set the response header Connection: close and most clients will terminate the connection from their side.

huangapple
  • 本文由 发表于 2012年6月11日 03:46:40
  • 转载请务必保留本文链接:https://go.coder-hub.com/10971800.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定