2012-06-10 17 views
19

He instalado un servidor http escrito en Go y recibe un poco más de mil visitantes por día. Tengo un problema de acumulación de Goroutine ahora. En el transcurso de un día, parece que recibo un poco más de mil nuevos Goroutines del servidor http.Golang: servidor http dejando los goroutines abiertos

No estoy seguro de cómo podría estropear el controlador.

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

abajo es uno de los goroutines de la pila

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 

Parece que las conexiones se queda pegada en el estado de lectura. Al igual que el servidor http no los está agotando. ¿El servidor predeterminado no tiene un tiempo de espera de lectura?

versión marcha go1

Respuesta

54

La razón de todos estos goroutines están leyendo es conexión persistente. Cuando un navegador envía un encabezado keep-alive, el servidor mantiene la conexión abierta para aceptar más solicitudes. Esto es bueno cuando el cliente está solicitando muchos archivos pequeños y la conexión TCP es una sobrecarga significativa. Un tiempo de espera de lectura garantizaría que no se mantuviera activa la conexión más de un cierto tiempo entre las solicitudes. Esto cerraría las conexiones de mantener activas pero también evitaría que alguien cargue durante más tiempo que el tiempo de espera. Desafortunadamente, todavía no hay una opción de tiempo de espera específico para mantener vivo.

De forma predeterminada, no hay tiempo de espera. Se puede establecer un tiempo de espera en la estructura del servidor http://golang.org/pkg/net/http/#Server

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

Gracias! Lo probaré para nuestra actualización esta semana. :-) – Daniel

+1

Sí, eso lo solucionó. ¡Gracias! – Daniel

+0

¿Podría marcarlo como respondido? Gracias –

0

tener cuidado al usar ReadTimeout y WriteTimeout en las conexiones HTTP. No creo que hagan lo que usted espera que hagan. En particular, tienen una tendencia a dejar las conexiones en un estado inutilizable sin realmente cerrarlas. Consulte https://groups.google.com/forum/#!topic/golang-nuts/oBIh_R7-pJQ para obtener detalles, en particular, veo casos en los que un ReadTimeout inutiliza las conexiones y hace que las respuestas se eliminen en el piso cuando el tiempo del manejador HTTP excede el tiempo de espera. Si configura el tiempo de espera en un valor grande que exceda el tiempo de respuesta de cualquier controlador, puede estar bien.

0

La respuesta de Stephen funcionó solo para mí en combinación con lo siguiente: el servidor puede decirle a sus clientes que no desea o no admite mantener las conexiones abiertas. Para ello, establezca el indicador de acuerdo antes de servir:

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

Esto establecerá la cabecera de respuesta Connection: close y la mayoría de los clientes se terminará la conexión de su lado.