-
-
Notifications
You must be signed in to change notification settings - Fork 2.4k
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
Example : Ensure that http connection will be re-use #249
Comments
It's not obvious to me that this is necessary. Can you point to something which indicates it is? |
of course : I have just tested in my own µservice (that uses gokit) and wireshark/tcpdump. I didn't test for the example, but I think that this example has to give the good way to do by re-using http connection. |
Huh, that's annoying! Yes, I agree it's a good idea. Can you please make a PR? Please visit the other examples too :) |
ok, I will do it |
Is it worth pointing out that |
I agree with @ChrisHines, maybe the comment can be modified to indicate this potential risk? |
I don't think our examples should include this io.Copy. I believe the linked posts arguing for its need are incorrect. See the current net/http implementation for https://github.com/golang/go/blob/master/src/net/http/transfer.go#L612 https://github.com/golang/go/blob/master/src/net/http/transfer.go#L777 As long as we |
@jerome-laforge I would be curious to learn why the connections were not reused in your tests. Maybe the server isn't returning a proper Content-Length or something. |
Maybe, but as already wrote in my previous post without this defer, the httpclient closes the tcp connection and open a new one. I checked this at raw level with wireshark. |
@ChrisHines I will check tomorrow if the Content-Length is ok or not. |
@ChrisHines I've just done a new test. As you can see:
A weird thing is that JSON decoder reads all data from r.Body because if I put this to monitor what is actually read into response.Body defer func() {
b := new(bytes.Buffer)
io.Copy(b, response.Body)
fmt.Println("--------------->", b.Len())
fmt.Println(hex.Dump(b.Bytes()))
fmt.Println("###############>")
}() I have this into the console:
However I see the httpclient that closed the TCP connection (it sends TCP FIN ACK to http server) and open a new one. I think that I will describe this on golang nuts. |
As I replied on the go mailing list, I think you guys are hitting the same case as this nasty docker bug. In summary, |
I have tried to reproduce the issue with Go code and cannot get the described behavior. Take a look at this code, run it, and see if you agree: https://play.golang.org/p/XtCIhjL1z3 |
I run it with -race and the code is racy.
I try to quickly fix the race with this : https://play.golang.org/p/0_Uq5C8Z3Y I have this:
After this I tried two http request on the same test server without io.Copy(discard, r.Body). Plz find the code here: The result:
In this case, I can see with wireshark the httpclient close 1st tcp conn with reset and open a new one for 2nd req that closes again with reset. As you can see.
If I do the same test (2 http request) but with purge of r.Body, plz find the code here: In this case, I can see with wireshark that httpclient has reused the tcp conn for both http request, as expected. |
I get inconsistent results. Using your two-request code I can run it multiple times and get different results:
|
This code is not the core of the pb. It is just adaptation of your code without the race and that tries to point out that without the purge of the response.Body the httpclient doesn't reuse the tcp connection. |
@jerome-laforge Here is an updated version that is less racy: https://play.golang.org/p/aYFyASvAik With this code I sometimes see the connection close. If I uncomment the |
Forgive me, I became somewhat lost in the details. Is the current state here that we're seeing behavior we cannot currently explain? |
@peterbourgon That's where I am at. In my mind there seems to be a missing piece to the puzzle. |
For my point of view, this problem occurs when response is sent with And so we don't read the last 0 that indicates the end of response that normally happens here: |
It would seem to me, from reading this code, https://github.com/golang/go/blob/master/src/net/http/transfer.go#L777, that I contend that if it does not do this, either it has a good reason, or there is a bug in |
Looking at your results Chris it does seem that there is an issue with the payload received from the Server. The first time the chunk length header is properly received being 0 meaning the request is done so the connection can be re-used safely. The second time this empty chunk header identifying end of request is not shown. If no data is available for reception in a reasonable amount of time we can't assume this connection to be reusable as many large chunks could potentially be received afterwards. |
@ChrisHines delve shows me that when https://github.com/golang/go/blob/master/src/net/http/internal/chunked.go#L61 returns 0, the https://github.com/golang/go/blob/master/src/net/http/transfer.go#L777 isn't called cause https://github.com/golang/go/blob/master/src/net/http/transport.go#L1870 is executed before https://github.com/golang/go/blob/master/src/net/http/transport.go#L1872. |
@jerome-laforge Then maybe you have found a bug. What version of Go are you testing this on? See also this long discussion of pretty much the same issue: google/go-github#317. This may already be fixed on tip: https://go-review.googlesource.com/#/c/21291. |
@ChrisHines I use Go on Arch Linux, and my version of Go is:
I will fetch Go tip, I will try the test with it. |
@ChrisHines I have just tested with tip version: |
@jerome-laforge I recommend opening an issue against Go net/http package. |
@jerome-laforge The issue you filed against Go was closed. See the Go issue to see if you are satisfied with the explanation. Please let us know if we can close this issue. |
Yes, you can close it. I will keep drain of response.Body to ensure the reuse of connection. |
Hello,
It will be great into example to ensure that http connection will be re-use by ensuring that Body has be completely purged. That avoid performance problem for whom that use this example as primary guide.
For example for https://github.com/go-kit/kit/blob/master/examples/stringsvc3/transport.go#L50, add something like this :
Thx.
The text was updated successfully, but these errors were encountered: