go net/http Client 使用——长连接客户端的使用
hardecz 2017-12-06 15:46:40
17705
收藏 3
最后发布: 2017-12-06 15:46:40 首次发布: 2017-12-06 15:46:40
go net/http Client 使用总结
Client 数据结构
`2. // A Client is an HTTP client. Its zero value (DefaultClient) is a
3. // usable client that uses DefaultTransport.
4. //
5. // The Client's Transport typically has internal state (cached TCP
6. // connections), so Clients should be reused instead of created as
7. // needed. Clients are safe for concurrent use by multiple goroutines.
8. //
9. // A Client is higher-level than a RoundTripper (such as Transport)
10. // and additionally handles HTTP details such as cookies and
11. // redirects.
12. type Client struct {
13. // Transport specifies the mechanism by which individual
14. // HTTP requests are made.
15. // If nil, DefaultTransport is used.
16. Transport RoundTripper
18. // CheckRedirect specifies the policy for handling redirects.
19. // If CheckRedirect is not nil, the client calls it before
20. // following an HTTP redirect. The arguments req and via are
21. // the upcoming request and the requests made already, oldest
22. // first. If CheckRedirect returns an error, the Client's Get
23. // method returns both the previous Response (with its Body
24. // closed) and CheckRedirect's error (wrapped in a url.Error)
25. // instead of issuing the Request req.
26. // As a special case, if CheckRedirect returns ErrUseLastResponse,
27. // then the most recent response is returned with its body
28. // unclosed, along with a nil error.
29. //
30. // If CheckRedirect is nil, the Client uses its default policy,
31. // which is to stop after 10 consecutive requests.
32. CheckRedirect func(req *<span class="" "="">Request, via []*Request) error
34. // Jar specifies the cookie jar.
35. // If Jar is nil, cookies are not sent in requests and ignored
36. // in responses.
37. Jar CookieJar
39. // Timeout specifies a time limit for requests made by this
40. // Client. The timeout includes connection time, any
41. // redirects, and reading the response body. The timer remains
42. // running after Get, Head, Post, or Do return and will
43. // interrupt reading of the Response.Body.
44. //
45. // A Timeout of zero means no timeout.
46. //
47. // The Client cancels requests to the underlying Transport
48. // using the Request.Cancel mechanism. Requests passed
50. ay still set Request.Cancel; both will
51. // cancel the request.
52. //
53. // For compatibility, the Client will also use the deprecated
54. // CancelRequest method on Transport if found. New
55. // RoundTripper implementations should use Request.Cancel
56. // instead of implementing CancelRequest.
57. Timeout time.Duration
58. }`
注意Transport
数据结构,对应如下:
`1. // Transport is an implementation of RoundTripper that supports HTTP,
2. // HTTPS, and HTTP proxies (for either HTTP or HTTPS with CONNECT).
3. //
4. // By default, Transport caches connections for future re-use.
5. // This may leave many open connections when accessing many hosts.
6. // This behavior can be managed using Transport's CloseIdleConnections method
7. // and the MaxIdleConnsPerHost and DisableKeepAlives fields.
8. //
9. // Transports should be reused instead of created as needed.
10. // Transports are safe for concurrent use by multiple goroutines.
11. //
12. // A Transport is a low-level primitive for making HTTP and HTTPS requests.
13. // For high-level functionality, such as cookies and redirects, see Client.
14. //
15. // Transport uses HTTP/1.1 for HTTP URLs and either HTTP/1.1 or HTTP/2
16. // for HTTPS URLs, depending on whether the server supports HTTP/2.
17. // See the package docs for more about HTTP/2.
18. type Transport struct {
19. idleMu sync.Mutex
20. wantIdle bool // user has requested to close all idle conns
21. idleConn map[connectMethodKey][]*persistConn // most recently used at end
22. idleConnCh map[connectMethodKey]chan *persistConn
23. idleLRU connLRU
25. reqMu sync.Mutex
26. reqCanceler map[*Request]func()
28. altMu sync.RWMutex
29. altProto map[string]RoundTripper // nil or map of URI scheme => RoundTripper
31. // Proxy specifies a function to return a proxy for a given
32. // Request. If the function returns a non-nil error, the
33. // request is aborted with the provided error.
34. // If Proxy is nil or returns a nil *URL, no proxy is used.
35. Proxy func(*Request) (*url.URL, error)
37. // DialContext specifies the dial function for creating unencrypted TCP connections.
38. // If DialContext is nil (and the deprecated Dial below is also nil),
39. // then the transport dials using package net.
40. DialContext func(ctx context.Context, network, addr string) (net.Conn, error)
42. // Dial specifies the dial function for creating unencrypted TCP connections.
43. //
44. // Deprecated: Use DialContext instead, which allows the transport
45. // to cancel dials as soon as they are no longer needed.
46. // If both are set, DialContext takes priority.
47. Dial func(network, addr string) (net.Conn, error)
49. // DialTLS specifies an optional dial function for creating
50. // TLS connections for non-proxied HTTPS requests.
51. //
52. // If DialTLS is nil, Dial and TLSClientConfig are used.
53. //
54. // If DialTLS is set, the Dial hook is not used for HTTPS
55. // requests and the TLSClientConfig and TLSHandshakeTimeout
56. // are ignored. The returned net.Conn is assumed to already be
57. // past the TLS handshake.
58. DialTLS func(network, addr string) (net.Conn, error)
60. // TLSClientConfig specifies the TLS configuration to use with
61. // tls.Client. If nil, the default configuration is used.
62. TLSClientConfig *tls.Config
64. // TLSHandshakeTimeout specifies the maximum amount of time waiting to
65. // wait for a TLS handshake. Zero means no timeout.
66. TLSHandshakeTimeout time.Duration
68. // DisableKeepAlives, if true, prevents re-use of TCP connections
69. // between different HTTP requests.
70. DisableKeepAlives bool
72. // DisableCompression, if true, prevents the Transport from
73. // requesting compression with an "Accept-Encoding: gzip"
74. // request header when the Request contains no existing
75. // Accept-Encoding value. If the Transport requests gzip on
76. // its own and gets a gzipped response, it's transparently
77. // decoded in the Response.Body. However, if the user
78. // explicitly requested gzip it is not automatically
79. // uncompressed.
80. DisableCompression bool
82. // MaxIdleConns controls the maximum number of idle (keep-alive)
83. // connections across all hosts. Zero means no limit.
84. MaxIdleConns int
86. // MaxIdleConnsPerHost, if non-zero, controls the maximum idle
87. // (keep-alive) connections to keep per-host. If zero,
88. // DefaultMaxIdleConnsPerHost is used.
89. MaxIdleConnsPerHost int
91. // IdleConnTimeout is the maximum amount of time an idle
92. // (keep-alive) connection will remain idle before closing
93. // itself.
94. // Zero means no limit.
95. IdleConnTimeout time.Duration
97. // ResponseHeaderTimeout, if non-zero, specifies the amount of
98. // time to wait for a server's response headers after fully
99. // writing the request (including its body, if any). This
100. // time does not include the time to read the response body.
101. ResponseHeaderTimeout time.Duration
103. // ExpectContinueTimeout, if non-zero, specifies the amount of
104. // time to wait for a server's first response headers after fully
105. // writing the request headers if the request has an
106. // "Expect: 100-continue" header. Zero means no timeout.
107. // This time does not include the time to send the request header.
108. ExpectContinueTimeout time.Duration
110. // TLSNextProto specifies how the Transport switches to an
111. // alternate protocol (such as HTTP/2) after a TLS NPN/ALPN
112. // protocol negotiation. If Transport dials an TLS connection
113. // with a non-empty protocol name and TLSNextProto contains a
114. // map entry for that key (such as "h2"), then the func is
115. // called with the request's authority (such as "example.com"
116. // or "example.com:1234") and the TLS connection. The function
117. // must return a RoundTripper that then handles the request.
118. // If TLSNextProto is nil, HTTP/2 support is enabled automatically.
119. TLSNextProto map[string]func(authority string, c *tls.Conn) RoundTripper
121. // MaxResponseHeaderBytes specifies a limit on how many
122. // response bytes are allowed in the server's response
123. // header.
124. //
125. // Zero means to use a default limit.
126. MaxResponseHeaderBytes int64
128. // nextProtoOnce guards initialization of TLSNextProto and
129. // h2transport (via onceSetNextProtoDefaults)
130. nextProtoOnce sync.Once
131. h2transport *http2Transport // non-nil if http2 wired up
133. // TODO: tunable on max per-host TCP dials in flight (Issue 13957)
134. }`
实际上是一个连接池,所以在使用的过程中通常是初始化一个Transport
和Client
,在每个处理函数中都共用该连接池,例如如下 Demo:
`
1. package main
3. import (
4. "bytes"
5. "io/ioutil"
6. "log"
7. "net"
8. "net/http"
9. "time"
10. )
12. var (
13. httpClient *http.Client
14. )
16. // init HTTPClient
17. func init() {
18. httpClient = createHTTPClient()
19. }
21. const (
22. MaxIdleConns int = 100
23. MaxIdleConnsPerHost int = 100
24. IdleConnTimeout int = 90
25. )
27. // createHTTPClient for connection re-use
28. func createHTTPClient() *http.Client {
29. client := &http.Client{
30. Transport: &http.Transport{
31. Proxy: http.ProxyFromEnvironment,
32. DialContext: (&net.Dialer{
33. Timeout: 30 * time.Second,
34. KeepAlive: 30 * time.Second,
35. }).DialContext,
36. MaxIdleConns: MaxIdleConns,
37. MaxIdleConnsPerHost: MaxIdleConnsPerHost,
38. IdleConnTimeout: time.Duration(_IdleConnTimeout_)* time.Second,
39. },
`
Timeout: 20 \* time._Second_,
`1. }
2. return client
3. }
5. func main() {
6. var endPoint string = "https://localhost:8080/doSomething"
8. req, err := http.NewRequest("POST", endPoint, bytes.NewBuffer([]byte("Post this data")))
9. if err != nil {
10. log.Fatalf("Error Occured. %+v", err)
11. }
12. req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
14. // use httpClient to send request
15. response, err := httpClient.Do(req)
16. if err != nil && response == nil {
17. log.Fatalf("Error sending request to API endpoint. %+v", err)
18. } else {
19. // Close the connection to reuse it
20. defer response.Body.Close()
22. // Let's check if the work actually is done
23. // We have seen inconsistencies even when we get 200 OK response
24. body, err := ioutil.ReadAll(response.Body)
25. if err != nil {
26. log.Fatalf("Couldn't parse response body. %+v", err)
27. }
29. log.Println("Response Body:", string(body))
30. }
32. }`
下面详细讲解Transport
结构需要注意的几个参数设置:
- DisableKeepAlives
`
1. // DisableKeepAlives, if true, prevents re-use of TCP connections
2. // between different HTTP requests.
`
表示是否开启 http keepalive 功能,也即是否重用连接,默认开启 (false)
- MaxIdleConns
`
1. // MaxIdleConns controls the maximum number of idle (keep-alive)
2. // connections across all hosts. Zero means no limit.
`
表示连接池对所有 host 的最大链接数量,host 也即 dest-ip,默认为无穷大(0),但是通常情况下为了性能考虑都要严格限制该数目(实际使用中通常利用压测 二分得到该参数的最佳近似值)。太大容易导致客户端和服务端的 socket 数量剧增,导致内存吃满,文件描述符不足等问题;太小则限制了连接池的 socket 数量,资源利用率较低。
- MaxIdleConnsPerHost
`
1. // MaxIdleConnsPerHost, if non-zero, controls the maximum idle
2. // (keep-alive) connections to keep per-host. If zero,
3. // DefaultMaxIdleConnsPerHost is used.
`
表示连接池对每个 host 的最大链接数量,从字面意思也可以看出:
`MaxIdleConnsPerHost <= MaxIdleConns`
如果客户端只需要访问一个 host,那么最好将MaxIdleConnsPerHost
与MaxIdleConns
设置为相同,这样逻辑更加清晰。
- IdleConnTimeout
`
1. // IdleConnTimeout is the maximum amount of time an idle
2. // (keep-alive) connection will remain idle before closing
3. // itself.
4. // Zero means no limit.
`
空闲 timeout 设置,也即 socket 在该时间内没有交互则自动关闭连接(注意:该 timeout 起点是从每次空闲开始计时,若有交互则重置为 0), 该参数通常设置为分钟级别,例如:90 秒。
- DialContext
`
1. // DialContext specifies the dial function for creating unencrypted TCP connections.
2. // If DialContext is nil (and the deprecated Dial below is also nil),
3. // then the transport dials using package net.
4. DialContext func(ctx context.Context, network, addr string) (net.Conn, error)
`
该函数用于创建 http(非 https)连接,通常需要关注Timeout
和KeepAlive
参数。前者表示建立 Tcp 链接超时时间;后者表示底层为了维持 http keepalive 状态 每隔多长时间发送 Keep-Alive 报文。Timeout
通常设置为 30s(网络环境良好),KeepAlive
通常设置为 30s(与 IdleConnTimeout 要对应)。
补充说明
Transport
数据结构中的MaxConnsPerHost
参数目前正在研发中(Go 项目),其表示对每个 host 可以发出的最大连接个数(包括长链接和短链接),是非常有用的参数,可以用来对 socket 数量进行限制,配合MaxIdleConns
和MaxIdleConnsPerHost
一起使用。
net/http Transport MaxConnsPerHost