Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Golang: http server leaving open goroutines

Tags:

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

like image 241
Daniel Avatar asked Jun 10 '12 19:06

Daniel


People also ask

How do I get out of Goroutine gracefully?

Typically, you pass the goroutine a (possibly separate) signal channel. That signal channel is used to push a value into when you want the goroutine to stop. The goroutine polls that channel regularly. As soon as it detects a signal, it quits.

How do I stop HTTP server on go?

Simply shutdown HTTP serverRun a server and send a request to /shutdown , then the server stops.

How do you stop go routines?

One goroutine can't forcibly stop another. To make a goroutine stoppable, let it listen for a stop signal on a dedicated quit channel, and check this channel at suitable points in your goroutine. Here is a more complete example, where we use a single channel for both data and signalling.

Does ListenAndServe block?

If we look at the ListenAndServe function, it has the following syntax. When we call http. ListenAndServer() with appropriate arguments, it starts an HTTP server and blocks the current goroutine. If we run this function inside the main function, it will block the main goroutine (started by the main function).


1 Answers

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() 
like image 66
Stephen Weinberg Avatar answered Oct 06 '22 09:10

Stephen Weinberg