req, err := http.NewRequest(http.MethodPost, reqUrl, bytes.NewBuffer([]byte{}))
if err != nil {
continue
}
client := &http.Client{Timeout: 15 * time.Second}
resp, err := client.Do(req)
if err != nil {
continue
}
현재 대부분의 코드에서 http client 객체를 요청마다 생성하여 api 요청을 하고 있는데, golang에서는 기본적으로 connection pooling이 되어있음.
http.Client{}
는 DefaultTransport
를 사용하는데, 이는 커넥션 풀 사이즈를 정의하고 관리하며, 싱글톤으로 관리되어 Client 객체를 매 request마다 생성하더라도 기본적으로 pool을 사용하고 있다.
type Client struct {
// Transport specifies the mechanism by which individual
// HTTP requests are made.
// **If nil, DefaultTransport is used**.
Transport RoundTripper
CheckRedirect func(req *Request, via []*Request) error
Jar CookieJar
Timeout time.Duration
}
중점적으로 봐야할 것은 실질적으로 http request를 수행하는 Transport
// DefaultTransport is the default implementation of Transport and is
// used by DefaultClient. It establishes network connections as needed
// and **caches them for reuse by subsequent calls**. It uses HTTP proxies
// as directed by the $HTTP_PROXY and $NO_PROXY (or $http_proxy and
// $no_proxy) environment variables.
var DefaultTransport RoundTripper = &Transport{
Proxy: ProxyFromEnvironment,
DialContext: defaultTransportDialContext(&net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
}),
ForceAttemptHTTP2: true,
MaxIdleConns: 100,
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
}
**// DefaultMaxIdleConnsPerHost is the default value of Transport's
// MaxIdleConnsPerHost.
const DefaultMaxIdleConnsPerHost = 2**
type Transport struct {
...
// MaxIdleConns controls the maximum number of idle (keep-alive)
// connections across all hosts. Zero means no limit.
MaxIdleConns int
// MaxIdleConnsPerHost, if non-zero, controls the maximum idle
// (keep-alive) connections to keep per-host. If zero,
// DefaultMaxIdleConnsPerHost is used.
MaxIdleConnsPerHost int
// MaxConnsPerHost optionally limits the total number of
// connections per host, including connections in the dialing,
// active, and idle states. On limit violation, dials will block.
//
// Zero means no limit.
MaxConnsPerHost int
...
}
connection pool에서 최대 100개의 idle connection을 유지하지만, DefaultMaxIdelConnsPerHost
의 값이 2로 되어 있다.
이 값은 호스트 당, idle한 connection이 최대 2개 → 재사용 커넥션 수 2
func startLoadTest() {
for {
startTime := time.Now()
resp, err := http.Get("<http://localhost:8080/>")
if err != nil {
panic(fmt.Sprintf("Got error: %v %v", err)
}
ioutil.ReadAll(resp.Body)
resp.Body.Close()
log.Printf("Finished GET request")
}
}
func main() {
for i := 0; i < 2; i++ {
go startLoadTest()
}
time.Sleep(time.Second * 2400)
}
netstat -n | grep -i 8080
tcp6 0 0 ::1.63138 ::1.8080 ESTABLISHED
tcp6 0 0 ::1.63137 ::1.8080 ESTABLISHED
func main() {
for i := 0; i < 6; i++ {
go startLoadTest()
}
time.Sleep(time.Second * 2400)
}
최초 연결
tcp6 0 0 ::1.63049 ::1.8080 ESTABLISHED
tcp6 0 0 ::1.63047 ::1.8080 ESTABLISHED
tcp6 0 0 ::1.63048 ::1.8080 ESTABLISHED
tcp6 0 0 ::1.63046 ::1.8080 ESTABLISHED
**tcp6 0 0 ::1.63045 ::1.8080 ESTABLISHED
tcp6 0 0 ::1.63044 ::1.8080 ESTABLISHED**