go x/net/http2: 在高负载性能测试中连接被错误地重置

dsekswqp  于 4个月前  发布在  Go
关注(0)|答案(8)|浏览(47)

你正在使用的Go版本是什么( go version )?

golang:1.10.0 linux

这个问题在最新版本的发布中是否重现?

是的

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

容器:rhel
kubenet:

你做了什么?

func (sc *serverConn) wroteFrame(res frameWriteResult) {
...
			sc.closeStream(st, errHandlerComplete)                  <=== _code1_
		}
...
	wr.replyToWriter(res.err)                                               <=== _code2_
...
}

在某些情况下,服务器goroutine将在code1code2之间切换执行上下文。如果处理程序goroutine在这些情况下切换回执行上下文,这将使writeDataFromHandler()(writeHeaders()也一样?)失败并将responseWriterState设置为脏。

func (sc *serverConn) writeDataFromHandler(stream *stream, data []byte, endStream bool) error {
...
	case <-stream.cw:
		// If both ch and stream.cw were ready (as might
		// happen on the final Write after an http.Handler
		// ends), prefer the write result. Otherwise this
		// might just be us successfully closing the stream.
		// The writeFrameAsync and serve goroutines guarantee
		// that the ch send will happen before the stream.cw
		// close.
		select {
		case err = <-ch:
			frameWriteDone = true
		default:
			return errStreamClosed
		}
	}
...
}
func (rws *responseWriterState) writeChunk(p []byte) (n int, err error) {
...
		if err := rws.conn.writeDataFromHandler(rws.stream, p, endStream); err != nil {
			rws.dirty = true
			return 0, err
		}
...
}

**如果在负载性能测试中在code1code2之间添加sc.logf(),这个问题可以很容易地重现。

PS:我认为在writeFrame()中,当我们用错误关闭流时,我们不应该调用"wr.replyToWriter(res.err)",这会导致writeDataFromHandler()退出没有错误。但实际上,这个流/responseWriterState已经处于错误状态。**

你期望看到什么?

负载测试中没有连接重置

你看到了什么?

连接重置和在新连接建立之前流量失败

7qhs6swi

7qhs6swi1#

@bradfitz @tombergan

fkaflof6

fkaflof64#

我尝试了使用h2load作为客户端和返回100-16k字节数据的服务器。无论在服务器端开启调试,我都无法引起任何连接重置问题,导致显著的减速。

roqulrg3

roqulrg35#

你好Fraenkel,

这个问题在低负载性能测试中很容易重现。如果在code1和code2之间添加sc.logf(),就可以轻松重现这个问题。你需要大量的流,并且在一个连接中传输较少的数据才能重现它。例如,创建一个每秒3000个或更多的流的连接,然后传输并关闭它。

B.R

7dl7o3gd

7dl7o3gd6#

在您的代码1和代码2之间的多个地方,我已经添加了sc.logf()。但是在使用h2load驱动时,我仍然没有遇到任何错误。它显示我实现了7150 req/s的速率。我也尝试了有调试和没有调试来减慢速度,但这也没有导致任何错误。

6tqwzwtp

6tqwzwtp7#

请问7150 req/s是否属于一个连接到Go语言HTTP2服务器的请求?7150响应/s的响应体中是否有一些内容?

i7uq4tfw

i7uq4tfw8#

是的,有超过10k个流被创建。我尝试了较小和较大的有效载荷,但都是恒定大小。
如果你能捕获http2debug,那可能会有助于缩小问题范围,因为我似乎无法在最新的代码库上本地进行操作。

相关问题