2012-06-10 6 views
19

ho messo su un server HTTP scritto in Go e sta diventando un po 'più di mille visitatori al giorno. Ho un problema di goroutine che si sta accumulando ora. Nel corso di un giorno mi sembra di ottenere un po 'più di mille nuove Goroutine dal server http.Golang: http server di lasciare aperte goroutines

non so come avrei potuto rovinare il gestore.

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

Qui di seguito è uno dei goroutines dalla 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 

Sembra che le connessioni sono sempre bloccati nello stato di lettura. Come il server http non li sta temporizzando. Il server predefinito non ha un timeout di lettura?

versione go GO1

risposta

54

La ragione per tutti questi goroutines sono la lettura è keep-alive. Quando un browser invia un'intestazione keep-alive, il server mantiene aperta la connessione per accettare più richieste. Questa è una buona cosa quando il client richiede molti piccoli file e la connessione TCP è un sovraccarico significativo. Un timeout di lettura assicurerebbe che nessuna connessione è stata mantenuta in vita più di un certo intervallo di tempo tra le richieste. Ciò chiuderebbe le connessioni keep alive ma impedirà anche a qualcuno di caricarsi più a lungo del timeout. Sfortunatamente, non esiste ancora un'opzione di timeout specifico keep-alive.

Per impostazione predefinita, non v'è alcun timeout. È possibile impostare un timeout nel struct 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() 
+0

Grazie! Darò una prova per il nostro aggiornamento questa settimana. :-) – Daniel

+1

Sì, è stato risolto. Grazie! – Daniel

+0

Potrebbe contrassegnarlo come risposta? Grazie –

0

Fare attenzione all'uso ReadTimeout e WriteTimeout su connessioni HTTP. Non penso che facciano come ti aspetti. In particolare, hanno la tendenza a lasciare le connessioni in uno stato inutilizzabile senza effettivamente chiuderle. Vedere https://groups.google.com/forum/#!topic/golang-nuts/oBIh_R7-pJQ per i dettagli, in particolare, vedo casi in cui ReadTimeout rende inutilizzabili le connessioni e causa la caduta delle risposte sul pavimento quando il tempo del gestore HTTP supera il timeout. Se si imposta il timeout su un valore elevato che supera il tempo di risposta di qualsiasi gestore, potrebbe essere OK.

0

risposta di Stephen ha lavorato per me solo in combinazione con il seguente: il server può dire ai suoi clienti che non desiderano o di supporto per mantenere le connessioni aperte. Per fare ciò, impostare il flag di secondo prima di servire:

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

Questo imposterà l'header di risposta Connection: close e maggior clienti terminerà la connessione dal loro lato.