go x/net/http2: allow setting MaxConcurrentStreams on client

uidvcgyl  于 5个月前  发布在  Go
关注(0)|答案(7)|浏览(47)

你正在使用哪个版本的Go(go version)?

$ go version
go version go1.19.13 linux/amd64

这个问题在最新版本中是否会重现?

是的

你正在使用什么操作系统和处理器架构(go env)?

go env 输出

$ go env
GO111MODULE=""
GOARCH="amd64"
GOBIN=""
GOCACHE="/root/.cache/go-build"
GOENV="/root/.config/go/env"
GOEXE=""
GOEXPERIMENT=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOINSECURE=""
GOMODCACHE="/root/go/pkg/mod"
GOOS="linux"
GOPATH="/root/go"
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/usr/local/go"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/usr/local/go/pkg/tool/linux_amd64"
GOVCS=""
GOVERSION="go1.19.13"
GCCGO="gccgo"
GOAMD64="v1"
AR="ar"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOWORK=""
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 -Wl,--no-gc-sections -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build2198329798=/tmp/go-build -gno-record-gcc-switches"

你做了什么?

我从http2.transport下载了9M个文件,使用了100个goroutine。

你期望看到什么?

目前http2中有超过100个活动流。我认为连接应该是新打开的,但它没有。

你看到了什么?

检查http2.transport连接池后,我们正在重用一个单一的连接。netstat -nap检查显示有1个连接,接收器已满,发送器已满很多。以下修改通过以20个活动流为单位创建连接来提高性能。

func (cc *ClientConn) State() ClientConnState {
	cc.wmu.Lock()
	maxConcurrent := cc.maxConcurrentStreams
	if !cc.seenSettings {
		maxConcurrent = 0
	}
	cc.wmu.Unlock()

+	// cc.mu.Lock()
+	// defer cc.mu.Unlock()
	return ClientConnState{
		Closed:               cc.closed,
		Closing:              cc.closing || cc.singleUse || cc.doNotReuse || cc.goAway != nil,
		StreamsActive:        len(cc.streams),
		StreamsReserved:      cc.streamsReserved,
		StreamsPending:       cc.pendingRequests,
		LastIdle:             cc.lastIdle,
		MaxConcurrentStreams: maxConcurrent,
	}
}
func (cc *ClientConn) idleStateLocked() (st clientConnIdleState) {
	if cc.singleUse && cc.nextStreamID > 1 {
		return
	}
	var maxConcurrentOkay bool
	if cc.t.StrictMaxConcurrentStreams {
		// We'll tell the caller we can take a new request to
		// prevent the caller from dialing a new TCP
		// connection, but then we'll block later before
		// writing it.
		maxConcurrentOkay = true
	} else {
		maxConcurrentOkay = int64(len(cc.streams)+cc.streamsReserved+1) <= int64(cc.maxConcurrentStreams)
	}

	st.canTakeNewRequest = cc.goAway == nil && !cc.closed && !cc.closing && maxConcurrentOkay &&
		!cc.doNotReuse &&
		int64(cc.nextStreamID)+2*int64(cc.pendingRequests) < math.MaxInt32 &&
		!cc.tooIdleLocked()

+	if st.canTakeNewRequest {
+		if cc.State().StreamsActive > 20 {
+			st.canTakeNewRequest = false
+		}
+	}
	return
}

随着活动流数量的增加,http2变得越来越慢。

icnyk63a

icnyk63a1#

感谢您的报告。请问您能否通过Playground链接发布您正在使用的代码?

8ehkhllq

8ehkhllq2#

@neild@tombergan per owners

qlvxas9a

qlvxas9a3#

测试代码在这里。
https://go.dev/play/p/et4HPzU3wLq?v=goprev
我在我的机器上检查了1个连接。
总响应时间为10秒。
在http1.1中,响应时间在2秒以内。
http2

time is 10.555606421

http1.1

time is 1.013303016s
mwkjh3gx

mwkjh3gx4#

请让我知道如果你需要任何更多的信息。

cbeh67ev

cbeh67ev5#

请注意,服务器可以设置MaxConcurrentStreams,通过#47840也可以实现类似的性能改进。

vm0i2vca

vm0i2vca6#

我认为我们需要在客户端上设置MaxConcurrentStreams。(http2.transport)
除了go服务器之外,我还使用了诸如go反向代理、nginx等服务器。如果Golang成为客户端,情况也是一样的。
MaxReadFrameSize会波动,但数值保持不变。

9nvpjoqh

9nvpjoqh7#

我正在寻找一些新的东西并与你分享。
我的当前电脑是56核CPU。
你已经设置了runtime.GOMAXPROCS(3)。
http2从10秒变为4秒。
http1从1秒变为4秒。

相关问题