我想尽快发送相当大数量(几千)的HTTP请求,而不给CDN(有https:URL,ALPN在TLS阶段选择HTTP/2)因此,交错(即时移)请求是一个选项,但我不想等待太长时间(最小化错误和总往返时间),而且我还没有受到服务器在我运营的规模上的速率限制。
我看到的问题源于h2_bundle.go
,特别是在writeFrame
或onWriteTimeout
中,此时大约有500- 1 k个请求正在传输,这在io.Copy(fileWriter, response.Body)
期间表现为:
http2ErrCodeInternal = "INTERNAL_ERROR" // also IDs a Stream number
// ^ then io.Copy observes the reader encountering "unexpected EOF"
现在我很好地坚持使用HTTP/1.x,但我希望得到一个解释:发生了什么。很明显,人们确实使用Go语言在单位时间内进行了很多次往返,但我能找到的大多数建议都是从服务器的Angular 出发的,而不是从客户端的Angular 。我已经尝试过指定所有相关的超时,并提高连接池的最大大小。
1条答案
按热度按时间atmip9wb1#
以下是我对这一切的最佳猜测:
HTTP/2内部的请求速率超过了连接队列或其他一些资源。也许这在一般情况下是可以修复的,或者可以针对我的特定用例进行微调,但克服这类问题的最快方法是完全依赖HTTP/1.1,以及实现有限的重试+速率限制机制。
另外,除了禁用HTTP/2的“丑陋的攻击”之外,我现在还使用一次重试和www.example.com中的
rate.Limiter
https://pkg.go.dev/golang.org/x/time/rate#Limiter,这样出站请求能够发送M个请求的初始“突发”,然后以给定的N/秒速率“逐渐泄漏”。来自h2_bundle.go
的错误对于最终用户来说太难解析了。2一个预期的/意外的EOF应该导致客户端“再试一次”或两次,无论如何这是更实用的。根据文档,在运行时禁用Go语言
http.Client
中h2的最简单方法是env GODEBUG=http2client=0 ...
,我也可以通过其他方法来实现。尤其需要理解的是,“下一个协议”是在TLS过程中“早期”预先协商的,因此Go语言的http.Transport
必须管理该配置沿着缓存/备忘录,以高效的方式提供其功能。因此,使用您自己的httpClient
到.Do(req)
(别忘了给予您的请求一个context.Context
,这样很容易取消),使用自定义的http.RoundTripper
进行传输。这使我能够生成所需的请求量,或者在边缘情况下获得更合理的错误。