Go HTTP空闲连接池和HTTP跟踪

huangapple go评论73阅读模式
英文:

Go HTTP idle connection pool and http trace

问题

我有一个长时间运行的GO程序(版本1.18),它使用RESTY每秒同时发送数百个GET请求到远程的https://api.abcd.com。每个GET请求都是一个单独的go协程,它使用相同的RESTY客户端。

远程服务器https://api.abcd.com是nginx/1.19.2(HTTP/2),IP地址是11.11.11.11和22.22.22.22。是的,这个远程服务器有多个IP地址。

我在设置RESTY客户端时使用主机名
SetBaseURL("https://api.abcd.com")

RESTY中的传输配置是默认的配置。

在RESTY客户端中启用了TraceInfo()。在跟踪信息中有一个"IsConnReused"字段。这个IsConnReused实际上来自GO httptrace包中的GotConnInfo结构体:

type GotConnInfo struct {
	Conn net.Conn

	// Reused表示此连接是否已被用于另一个HTTP请求。
	Reused bool

	// WasIdle表示此连接是否来自空闲连接池。
	WasIdle bool

	// 如果WasIdle为true,则IdleTime报告连接之前空闲的时间。
	IdleTime time.Duration
}

问题1:GO httptrace是根据主机名(api.abcd.com)还是IP地址来确定"连接是否重用"的?

问题2:GO http包中的空闲连接池实际上是一个映射,键是connectMethodKey结构体类型。该结构体中的addr字段是主机名还是IP地址?

type connectMethodKey struct {
	proxy, scheme, addr string
	onlyH1              bool
}

这是我在TraceInfo()中找到的信息。当程序刚开始运行时,所有请求都发送到11.11.11.11:443。几分钟后,所有请求都发送到22.22.22.22,不再发送到11.11.11.11。然后,几分钟后,所有请求又开始发送到11.11.11.11,这次没有22.22.22.22。

问题3:当请求开始发送到22.22.22.22时,连接到11.11.11.11的套接字连接是空闲的,为什么GO http不再使用空闲连接?我不认为这些空闲连接已经超时了。

英文:

I have a long running GO program(version 1.18) which sends hundreds of GET requests simultaneously per second using RESTY to the remote https://api.abcd.com. Each GET request is a separate go-routine which uses the same RESTY client.

remote server https://api.abcd.com is nginx/1.19.2(HTTP/2), IP address is 11.11.11.11 and 22.22.22.22. Yes, this remoter server has multiple IP addresses.

I use hostname when setting RESTY client
SetBaseURL("https://api.abcd.com")

Transport configuration are default one in RESTY.

TraceInfo() is enabled on RESTY client side. There is a "IsConnReused" field in the trace info. This IsConnReused actually comes from struct GotConnInfo in GO httptrace package:

type GotConnInfo struct {
	Conn net.Conn

	// Reused is whether this connection has been previously used for another HTTP request.
	Reused bool

	// WasIdle is whether this connection was obtained from anidle pool.
	WasIdle bool

	// IdleTime reports how long the connection was previously idle, if WasIdle is true.
	IdleTime time.Duration
}

question 1: GO httptrace determine "Connection reused" based on hostname(api.abcd.com) or IP address?

question 2: GO http package idle connection pool is actually a map, key is a struct type connectMethodKey. The addr field in this struct is hostname or IP address?

type connectMethodKey struct {
	proxy, scheme, addr string
	onlyH1              bool
}

This is what I found in TraceInfo(). When the program runs at the beginning, all requests are sent to 11.11.11.11:443. Few minutes later, all requests are sent to 22.22.22.22, no 11.11.11.11 anymore. Then, few minutes later, all requests start to sent to 11.11.11.11 again, no 22.22.22.22 this time.

question 3: when requests start to sent to 22.22.22.22, the socket connections to 11.11.11.11 are idle, why GO http does not use idle connections anymore? I don't think those idle connection has already timeout.

答案1

得分: 0

问题1:GO的httptrace根据主机名(api.abcd.com)还是IP地址来确定“连接重用”?

httptrace.GotConnInfo.Reused是根据IP地址来跟踪TCP连接是否被用于另一个HTTP请求。

问题2:GO的http包中的空闲连接池实际上是一个映射,键是一个结构类型connectMethodKey。这个结构中的addr字段是主机名还是IP地址?

addrhostname

但如果你发送请求到类似http://127.0.0.1/这样的地址,它也可以是一个IP地址。

问题3:当请求开始发送到22.22.22.22时,连接到11.11.11.11的套接字连接是空闲的,为什么GO的http不再使用空闲连接?我不认为这些空闲连接已经超时了。

如果你使用HTTP 1,它可能会有不同的工作方式。在HTTP 1中,每个请求都需要自己的TCP连接。后续的请求可以重用TCP连接,但如果你想并行运行请求,你需要建立多个TCP连接。每个连接将使用不同的IP地址,你将看到流量均匀分布。

在HTTP/2中,一个TCP连接可以用于多个并行请求。该连接使用一个IP地址。

这是GO如何计算新请求是否可以使用打开的连接的方式:

https://cs.opensource.google/go/x/net/+/69896b71:http2/transport.go;l=881;drc=69896b714898bee1e3403560cd2e1870bcc8bd35;bpv=1;bpt=1

通过调整这些参数,可以将流量分布到多个TCP连接上。

英文:

> question 1: GO httptrace determine "Connection reused" based on
> hostname(api.abcd.com) or IP address?

httptrace.GotConnInfo.Reused tracks if TCP connection was used for another HTTP request. It is per IP address.

> question 2: GO http package idle connection pool is actually a map,
> key is a struct type connectMethodKey. The addr field in this struct
> is hostname or IP address?

addr is hostname

Could be an IP though if you send request to something like http://127.0.0.1/.

> question 3: when requests start to sent to 22.22.22.22, the socket
> connections to 11.11.11.11 are idle, why GO http does not use idle
> connections anymore? I don't think those idle connection has already
> timeout.

It could work differently if you use HTTP 1.
With it, every request requires the own TCP connection. Subsequent requests may reuse TCP connection, but if you want to run requests in parallel, you need to establish multiple TCP connections. Every connection would use a different IP address, and you would see traffic evenly distributed.

With HTTP/2 a single TCP connection can be used for multiple parallel requests. That connection uses a single IP address.

This is how GO calculates if a new request can use open connection:

https://cs.opensource.google/go/x/net/+/69896b71:http2/transport.go;l=881;drc=69896b714898bee1e3403560cd2e1870bcc8bd35;bpv=1;bpt=1

Play with these prams to distribute the traffic across multiple TCP connections.

huangapple
  • 本文由 发表于 2022年7月6日 08:42:59
  • 转载请务必保留本文链接:https://go.coder-hub.com/72876863.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定