golang の net.http で http keepalive を一定時間で切る方法
net.http を使って http request を送ると、デフォルトでは http keepalive が有効になります。("Connection: keep-alive" は送っていないけど、HTTP/1.1 ではデフォルトで keep-alive になるという背景もある。)
ですが、DNS ラウンドロビンを用いたロードバランサーに向けて接続をする場合等に、一定期間毎にコネクションを切って接続しなおしたいという場合があったりします。(そうしないと、DNS から外したサーバーにもアクセスが来続けるというような事が起きます。)
net.http には、keepalive を一定期間で切断する機能は存在しません。
ですが、transport を定期的に差し替えてやれば、実現は可能です。 (他に良い方法があったらぜひ教えてほしいです。)
package main
import (
"io/ioutil"
"net"
"net/http"
"sync"
"time"
)
type transportHolder struct {
transport *http.Transport
sync sync.Mutex
refreshDeadline time.Time
}
var th = transportHolder{}
func (th *transportHolder) getTransport() *http.Transport {
th.sync.Lock()
defer th.sync.Unlock()
if th.transport == nil || time.Now().After(th.refreshDeadline) {
// https://golang.org/src/net/http/transport.go
th.transport = &http.Transport{
Proxy: http.ProxyFromEnvironment,
DialContext: (&net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
DualStack: true,
}).DialContext,
MaxIdleConns: 100,
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
}
// 10秒ごとに transport を差し替える設定する例
th.refreshDeadline = time.Now().Add(10 * time.Second)
}
return th.transport
}
func main() {
for {
client := &http.Client{
Transport: th.getTransport(),
}
access(client)
time.Sleep(1 * time.Second)
}
}
func access(client *http.Client) {
resp, err := client.Get("http://localhost")
if err != nil {
panic(err)
}
defer resp.Body.Close()
println(resp.Status)
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
panic(err)
}
println(string(body))
}
次の記事があります golang の net.http で http keepalive を一定時間で切る方法(transport を使い回す)