[英]Golang: http2 client immediately close connections via proxy while idleConn was enabled
我正在使用 Go 來實現 http 客戶端和 squid 作為轉發代理向遠程服務器發送請求。 通過代理使用 http/1.1 或 http/1.1, http2 不使用代理時一切順利,但是,通過代理使用 http2 客戶端時,大多數連接立即關閉,只保留一兩個。
不確定這是我的錯誤代碼還是什么。 在 http 傳輸上啟用了 idleConn 配置。 提前致謝。
package main
import (
"context"
"crypto/tls"
"fmt"
"io"
"io/ioutil"
"net"
"net/http"
"net/url"
"sync"
"time"
)
const (
proxyURL = "http://{{proxy-ip}}:3128"
)
func main() {
wg := &sync.WaitGroup{}
wg.Add(1)
go func() {
doSendRequests()
wg.Done()
}()
wg.Wait()
}
func doSendRequests() {
//client := newHTTPClient(nil)
client := newHTTPClient(proxy)
round := 0
for {
round += 1
for i := 0; i < 5; i++ {
go func(r int) {
start := time.Now()
var err error
defer func() {
duration := time.Since(start)
fmt.Printf("Round: %d, A: %v, duration: %v\n", r, err, duration)
}()
req := newRequest("https://www.google.com")
resp, err := client.Do(req)
if err == nil {
io.Copy(ioutil.Discard, resp.Body)
resp.Body.Close()
} else {
fmt.Printf("A: %v\n", err)
}
}(round)
}
time.Sleep(100 * time.Second)
}
}
type TLSDialer struct {
net.Dialer
}
var (
config = &tls.Config{InsecureSkipVerify: true}
)
func (dialer *TLSDialer) DialContext(ctx context.Context, network, addr string) (net.Conn, error) {
return tls.DialWithDialer(&dialer.Dialer, network, addr, config)
}
var (
DefaultDialer = net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
DualStack: true,
}
DefaultTLSDialer = TLSDialer{DefaultDialer}
)
func proxy(req *http.Request) (*url.URL, error) {
uri, err := url.Parse(proxyURL)
if err != nil {
return nil, nil
}
return uri, nil
}
func newHTTPClient(proxy func(*http.Request) (*url.URL, error)) *http.Client {
t := &http.Transport{
DialContext: (&DefaultDialer).DialContext,
DisableKeepAlives: false,
DisableCompression: false,
ForceAttemptHTTP2: true,
MaxIdleConns: 5000,
MaxIdleConnsPerHost: 1000,
IdleConnTimeout: 0 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
}
if proxy == nil {
t.DialTLSContext = (&DefaultTLSDialer).DialContext
} else {
t.Proxy = proxy
t.TLSClientConfig = &tls.Config{
InsecureSkipVerify: true,
}
}
return &http.Client{Transport: t}
}
func newRequest(uri string) *http.Request {
ctx, _ := context.WithTimeout(context.Background(), 60*time.Second)
req, _ := http.NewRequestWithContext(ctx, "GET", uri, nil)
return req
}
go 1.15.3
GO111MODULE=""
GOARCH="amd64"
GOBIN=""
GOCACHE="/home/ec2-user/.cache/go-build"
GOENV="/home/ec2-user/.config/go/env"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOINSECURE=""
GOMODCACHE="/home/ec2-user/go/pkg/mod"
GONOPROXY=""
GONOSUMDB=""
GOOS="linux"
GOPATH="/home/ec2-user/go"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/usr/local/go"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/usr/local/go/pkg/tool/linux_amd64"
GCCGO="gccgo"
AR="ar"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD=""
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build200120630=/tmp/go-build -gno-record-gcc-switches"
unname -a
Linux ip-10-53-74-64.ec2.internal 4.14.243-185.433.amzn2.x86_64 #1 SMP Mon Aug 9 05:55:52 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux
魷魚 4.15
正如我在摘要中提到的,當我通過代理使用 http/1.1 或 http/1.1、http2 沒有代理時,一切都很順利。 但是,當通過代理使用 http2 客戶端時,將創建與請求一樣多的連接,然后關閉其他連接,只留下一兩個連接。 我使用 Wireshark 捕獲包,發現連接最初是從客戶端關閉的,因此代理端可能無關緊要,對此不確定。
// www.google.com
Every 0.5s: netstat -anop | grep '172.217'
Sat Nov 27 04:26:22 2021
tcp 0 0 10.53.74.64:44106 172.217.0.36:443 ESTABLISHED 3110/main keepalive (25.35/0/0)
tcp 0 0 10.53.74.64:44378 172.217.0.36:443 ESTABLISHED 3110/main keepalive (25.44/0/0)
tcp 0 0 10.53.74.64:44084 172.217.0.36:443 ESTABLISHED 3110/main keepalive (25.60/0/0)
tcp 0 0 10.53.74.64:44374 172.217.0.36:443 ESTABLISHED 3110/main keepalive (25.43/0/0)
tcp 0 0 10.53.74.64:44220 172.217.0.36:443 ESTABLISHED 3110/main keepalive (25.52/0/0)
Every 0.5s: netstat -anop | grep ":3128"
Sun Dec 5 13:09:44 2021
tcp 0 0 10.53.74.64:58370 {{proxy-ip}}:3128 ESTABLISHED 26322/main keepalive (23.70/0/0)
tcp 0 0 10.53.74.64:58366 {{proxy-ip}}:3128 ESTABLISHED 26322/main keepalive (23.70/0/0)
tcp 0 0 10.53.74.64:58374 {{proxy-ip}}:3128 ESTABLISHED 26322/main keepalive (23.70/0/0)
tcp 0 0 10.53.74.64:58368 {{proxy-ip}}:3128 ESTABLISHED 26322/main keepalive (23.69/0/0)
tcp 0 0 10.53.74.64:58372 {{proxy-ip}}:3128 ESTABLISHED 26322/main keepalive (23.70/0/0)
如下所示,其他連接在 ESTABLISHED 后不久關閉,並且在 http 傳輸上啟用了 idleConn 配置。
Sun Dec 5 13:19:35 UTC 2021
tcp 0 284 10.53.74.64:58414 {{proxy-ip}}:3128 ESTABLISHED 34301/main on (0.20/0/0)
tcp 0 284 10.53.74.64:58416 {{proxy-ip}}:3128 ESTABLISHED 34301/main on (0.19/0/0)
tcp 0 284 10.53.74.64:58410 {{proxy-ip}}:3128 ESTABLISHED 34301/main on (0.19/0/0)
tcp 0 284 10.53.74.64:58412 {{proxy-ip}}:3128 ESTABLISHED 34301/main on (0.19/0/0)
tcp 0 284 10.53.74.64:58418 {{proxy-ip}}:3128 ESTABLISHED 34301/main on (0.19/0/0)
Sun Dec 5 13:19:35 UTC 2021
tcp 0 89 10.53.74.64:58414 {{proxy-ip}}:3128 FIN_WAIT1 - on (0.14/0/0)
tcp 0 89 10.53.74.64:58416 {{proxy-ip}}:3128 FIN_WAIT1 - on (0.14/0/0)
tcp 0 365 10.53.74.64:58410 {{proxy-ip}}:3128 ESTABLISHED 34301/main on (0.14/0/0)
tcp 0 89 10.53.74.64:58412 {{proxy-ip}}:3128 FIN_WAIT1 - on (0.14/0/0)
tcp 0 89 10.53.74.64:58418 {{proxy-ip}}:3128 FIN_WAIT1 - on (0.14/0/0)
Sun Dec 5 13:19:35 UTC 2021
tcp 0 0 10.53.74.64:58414 {{proxy-ip}}:3128 TIME_WAIT - timewait (59.99/0/0)
tcp 0 0 10.53.74.64:58416 {{proxy-ip}}:3128 TIME_WAIT - timewait (59.99/0/0)
tcp 0 31 10.53.74.64:58410 {{proxy-ip}}:3128 ESTABLISHED 34301/main on (0.26/0/0)
tcp 0 0 10.53.74.64:58412 {{proxy-ip}}:3128 TIME_WAIT - timewait (59.99/0/0)
tcp 0 0 10.53.74.64:58418 {{proxy-ip}}:3128 TIME_WAIT - timewait (59.99/0/0)
這可以被最新的 golang 1.17.4(現在:2021-12-05)復制。 有沒有人可以提供一種方法來弄清楚為什么會發生這種情況? 謝謝。
EDIT1:所有請求都沒有錯誤地完成。
EDIT2:我在 Golang repo 上打開了一個問題,以防有人感興趣: https://github.com/golang/go/issues/50000
這是一個熟悉的代理端口號。
最后,我弄清楚了,一切都按預期工作,所以它與 net/http2 無關。
更多詳情請參考本期: https://github.com/golang/go/issues/50000 。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.