Drain response body properly for http connection pool (#6415)

Currently Go http connection pool was not being properly
utilized leading to degrading performance as the number
of concurrent requests increased.

As recommended by Go implementation, we have to drain the
response body and close it.
This commit is contained in:
Harshavardhana
2018-09-05 16:47:14 -07:00
committed by GitHub
parent 1961f2ef54
commit fd1b8491db
9 changed files with 82 additions and 17 deletions

View File

@@ -22,6 +22,8 @@ import (
"encoding/gob"
"errors"
"fmt"
"io"
"io/ioutil"
"net"
"net/http"
"reflect"
@@ -40,6 +42,28 @@ type Client struct {
serviceURL *xnet.URL
}
// closeResponse close non nil response with any response Body.
// convenient wrapper to drain any remaining data on response body.
//
// Subsequently this allows golang http RoundTripper
// to re-use the same connection for future requests.
func closeResponse(body io.ReadCloser) {
// Callers should close resp.Body when done reading from it.
// If resp.Body is not closed, the Client's underlying RoundTripper
// (typically Transport) may not be able to re-use a persistent TCP
// connection to the server for a subsequent "keep-alive" request.
if body != nil {
// Drain any remaining Body and then close the connection.
// Without this closing connection would disallow re-using
// the same connection for future uses.
// - http://stackoverflow.com/a/17961593/4465767
bufp := b512pool.Get().(*[]byte)
defer b512pool.Put(bufp)
io.CopyBuffer(ioutil.Discard, body, *bufp)
body.Close()
}
}
// Call - calls service method on RPC server.
func (client *Client) Call(serviceMethod string, args, reply interface{}) error {
replyKind := reflect.TypeOf(reply).Kind()
@@ -69,7 +93,7 @@ func (client *Client) Call(serviceMethod string, args, reply interface{}) error
if err != nil {
return err
}
defer response.Body.Close()
defer closeResponse(response.Body)
if response.StatusCode != http.StatusOK {
return fmt.Errorf("%v rpc call failed with error code %v", serviceMethod, response.StatusCode)

View File

@@ -21,6 +21,13 @@ import (
"sync"
)
var b512pool = sync.Pool{
New: func() interface{} {
buf := make([]byte, 512)
return &buf
},
}
// A Pool is a type-safe wrapper around a sync.Pool.
type Pool struct {
p *sync.Pool