-
Notifications
You must be signed in to change notification settings - Fork 18k
net/http: crash in Transport.queueForIdleConn(...) #42810
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
This looks like memory corruption. Have you tried running your program under the race detector? See https://blog.golang.org/race-detector . |
@davecheney thanks for the info. Will try to test it. BTW, we get another net/http related crash stack trace. panic: close of closed channel goroutine 27732906 [running]: panic(0xd52840, 0xfa4110) /usr/local/go/src/runtime/panic.go:1064 +0x545 fp=0xc00ecd33c0 sp=0xc00ecd32f8 pc=0x43a025 runtime.closechan(0xc00f5ebe00) /usr/local/go/src/runtime/chan.go:365 +0x25a fp=0xc00ecd3400 sp=0xc00ecd33c0 pc=0x408eda net/http.(*persistConn).roundTrip(0xc00ea685a0, 0xc01a7c3800, 0xc010707710, 0x0, 0x0) /usr/local/go/src/net/http/transport.go:2603 +0xb3a fp=0xc00ecd3718 sp=0xc00ecd3400 pc=0x752dda net/http.(*Transport).roundTrip(0xc000402280, 0xc00e266100, 0x30, 0x7f5be55f9188, 0x150) /usr/local/go/src/net/http/transport.go:582 +0xa65 fp=0xc00ecd3960 sp=0xc00ecd3718 pc=0x746f65 net/http.(*Transport).RoundTrip(0xc000402280, 0xc00e266100, 0xc000402280, 0x0, 0x0) /usr/local/go/src/net/http/roundtrip.go:17 +0x35 fp=0xc00ecd3998 sp=0xc00ecd3960 pc=0x72ccb5 net/http.send(0xc00e266100, 0xfb5940, 0xc000402280, 0x0, 0x0, 0x0, 0xc006cb7230, 0x203005, 0x1, 0x0) /usr/local/go/src/net/http/client.go:252 +0x453 fp=0xc00ecd3b40 sp=0xc00ecd3998 pc=0x6e8b93 net/http.(*Client).send(0xc0000d5230, 0xc00e266100, 0x0, 0x0, 0x0, 0xc006cb7230, 0x0, 0x1, 0x203005) /usr/local/go/src/net/http/client.go:176 +0xff fp=0xc00ecd3bc0 sp=0xc00ecd3b40 pc=0x6e857f net/http.(*Client).do(0xc0000d5230, 0xc00e266100, 0x0, 0x0, 0x0) /usr/local/go/src/net/http/client.go:718 +0x45f fp=0xc00ecd3d98 sp=0xc00ecd3bc0 pc=0x6ea59f net/http.(*Client).Do(...) /usr/local/go/src/net/http/client.go:586 |
Found one buz code change: 1st time to fully use httptrace strings.Builder currentTraceTime := time.Now() trace := &httptrace.ClientTrace{ GetConn: func(hostPort string) { fmt.Fprintf(&httptrace, "\n\tHttpTrace: |%s %v|", "GetConn", time.Since(currentTraceTime)) currentTraceTime = time.Now() }, DNSStart: func(dnsInfo httptrace.DNSStartInfo) { fmt.Fprintf(&httptrace, "%s %v|", "DNSStart", time.Since(currentTraceTime)) currentTraceTime = time.Now() }, DNSDone: func(dnsInfo httptrace.DNSDoneInfo) { fmt.Fprintf(&httptrace, "%s %v|", "DNSDone", time.Since(currentTraceTime)) currentTraceTime = time.Now() }, ConnectStart: func(network, addr string) { fmt.Fprintf(&httptrace, "%s %v|", "ConnectStart", time.Since(currentTraceTime)) currentTraceTime = time.Now() }, ConnectDone: func(network, addr string, err error) { fmt.Fprintf(&httptrace, "%s %v|", "ConnectDone", time.Since(currentTraceTime)) currentTraceTime = time.Now() }, TLSHandshakeStart: func() { fmt.Fprintf(&httptrace, "%s %v|", "TLSHandshakeStart", time.Since(currentTraceTime)) currentTraceTime = time.Now() }, TLSHandshakeDone: func(connState tls.ConnectionState, err error) { fmt.Fprintf(&httptrace, "%s %v|", "TLSHandshakeDone", time.Since(currentTraceTime)) currentTraceTime = time.Now() }, GotConn: func(connInfo httptrace.GotConnInfo) { fmt.Fprintf(&httptrace, "%s %v|", "GotConn", time.Since(currentTraceTime)) r.remoteAddr = util.ExtractIP(connInfo.Conn.RemoteAddr().String()) currentTraceTime = time.Now() }, WroteRequest: func(wrInfo httptrace.WroteRequestInfo) { fmt.Fprintf(&httptrace, "%s %v|", "WroteRequest", time.Since(currentTraceTime)) currentTraceTime = time.Now() }, GotFirstResponseByte: func() { fmt.Fprintf(&httptrace, "%s %v|", "GotFirstResponseByte", time.Since(currentTraceTime)) }, } |
Hi @davecheney Do you have any proposal for the HTTP trace usage? One idea is to lock in each hook. Thanks. |
Have a look at how we do it in github.com/davecheney/httpstat |
Hi @davecheney, Thanks for the help so much. httpstat seems mainly for a single HTTP request. For PRD usage, the net/http client requests concurrency may be quite high. I noticed one comment "some may be called after the request has completed or failed" for ClientTrace. I have a concern if there is data access racing for the shared variable between ClientTrace hook and the usage after getting the response, like reading or setting remoteAddr by the connInfo.Conn.RemoteAddr() from httptrace.GotConnInfo. // ClientTrace is a set of hooks to run at various stages of an outgoing // HTTP request. Any particular hook may be nil. Functions may be // called concurrently from different goroutines and some may be called // after the request has completed or failed. // // ClientTrace currently traces a single HTTP request & response // during a single round trip and has no hooks that span a series // of redirected requests. // // See https://blog.golang.org/http-tracing for more. type ClientTrace struct { |
There could be a possibility of data races during the different phases of ClientTrace as the memory ownership and happens before relationships are not (IMO) well defined for that use case. I would proceed cautiously and make heavy use of the race detector to check your work. Also, I should remind you that unlike many projects, the Go project does not use GitHub Issues for general discussion or asking questions. GitHub Issues are used for tracking bugs and proposals only. For asking questions, see:
|
Thanks for the reminder and all the help, which is truly impressive. I got such log: TLSHandshakeStart is after GotConn/WroteRequest, which means the variable shared between the trace hook and the usage after got response body may encounter race condition. One approach is to use atomic/mutex for the shared variables. HttpTrace: |GetConn 37.462µs|GotConn 136.729174ms|WroteRequest 44.956µs|TLSHandshakeStart 102.646256ms|TLSHandshakeDone 1.03µs| |
What version of Go are you using (
go version
)?Does this issue reproduce with the latest release?
Not sure. Only happened once in our PROD env.
What operating system and processor architecture are you using (
go env
)?PROD runtime env, there is no go.
What did you do?
Sending an HTTPS request, and Got crashed.
What did you expect to see?
Successfully sending out HTTPS request
What did you see instead?
The memory of idle connections list seems corrupted
The text was updated successfully, but these errors were encountered: