为什么 net/http 不考虑超过 30 秒的超时持续时间?

2024年 2月 11日 91.7k 0

为什么 net/http 不考虑超过 30 秒的超时持续时间?

php小编香蕉在探讨网络请求中的超时持续时间时发现,为什么net/http在设计中没有考虑超过30秒的超时时间限制?超时时间是指在发送请求后,如果在指定时间内没有收到响应,就会认为请求失败。在网络请求中,超时时间的设置是非常重要的,过短可能导致请求失败,过长则会浪费资源。通过分析,主要原因是在设计时考虑到了性能和资源的平衡,以及网络环境的不确定性。接下来,我们将详细解答这个问题。

问题内容

使用 golang 1.20.1。

在golang的net/http和context包中,我无法设置超过三十秒的超时。设置较短的超时效果很好,例如

代码:

log.infof("elasticsearch url is %v", elasticsearchurl)
client := &http.client{timeout: time.duration(time.second * 60)}
req, err := http.newrequest("get", listbackupsurl, nil)
if err != nil {
internalerror(w, fmt.sprintf("error creating request: %v", err))
return
}
req.setbasicauth(username, password)
resp, err := client.do(req)
if err != nil {
// handle error
internalerror(w, fmt.sprintf("error accessing elasticsearch: %v", err))
return
}

登录后复制

日志:

i0503 23:01:55.973821 1 somecode.go:85] url is http://elasticsearch.example.ingest:9200
e0503 23:02:25.976345 1 caller_handler.go:63] 500 internal server error: error accessing elasticsearch: get "http://elasticsearch.example.ingest:9200/_cat/snapshots/object-store-repo?v&s=id": dial tcp 1.2.3.4:9200: i/o timeout

登录后复制

超时时间是三十秒,而不是六十秒。

如果我使用 http.newrequestwithcontext(...) 并使用设置相同超时的上下文,我会得到相同的行为:

代码:

log.infof("elasticsearch url is %v", elasticsearchurl)
ctx, cancel := context.withtimeout(context.background(), time.duration(time.second * 60))
defer cancel()
req, err := http.newrequestwithcontext(ctx, "get", listbackupsurl, nil)
if err != nil {
internalerror(w, fmt.sprintf("error creating request: %v", err))
return
}
req.setbasicauth(username, password)
resp, err := client.do(req)
if err != nil {
// handle error
internalerror(w, fmt.sprintf("error accessing elasticsearch: %v", err))
return
}

登录后复制

日志:

i0503 23:31:10.941169 1 somecode.go:85] elasticsearch url is http://elasticsearch.example.ingest:9200
e0503 23:31:40.941642 1 caller_handler.go:63] 500 internal server error: error accessing elasticsearch: get "http://elasticsearch.example.ingest:9200/_cat/snapshots/object-store-repo?v&s=id": dial tcp 1.2.3.4:9200: i/o timeout

登录后复制

但是,如果我在任一方法中将超时更改为三秒 (time.duration(time.second * 3)),它将按预期工作:

I0503 23:44:17.622121 1 somecode.go:85] Elasticsearch URL is http://elasticsearch.example.ingest:9200
E0503 23:44:20.624795 1 caller_handler.go:63] 500 Internal Server Error: error accessing elasticsearch: Get "http://elasticsearch.example.ingest:9200/_cat/snapshots/object-store-repo?v&s=id": context deadline exceeded (Client.Timeout exceeded while awaiting headers)

登录后复制

解决方法

我会隔离问题以消除可能性,从而帮助缩小导致问题发生的原因。如果可能,请使用一小段代码,这样您就可以只处理您想要的内容。

要测试您的基础设施,httpstat 将帮助您模拟远程超时。示例:

func main() {

client := &http.Client{Timeout: time.Duration(time.Second * 200)}
req, err := http.NewRequest("GET", "https://www.php.cn/link/1a59ef90d1ea801448e1567d0896a99f/504?sleep=120000", nil)
if err != nil {
log.Fatal(err)
return
}

resp, err := client.Do(req)
if err != nil {
log.Fatal(err)
return
}

fmt.Println(resp)
}

登录后复制

如果您此时收到 dial tcp ip:port: i/o timeout timeout,那么您需要检查您的操作系统和防火墙。无论您在 go 中设置什么超时,都应该覆盖操作系统默认值,如果您以这种方式超时,则可能是防火墙(本地或远程)导致了这种情况。

或者,如果您能够从外部连接,则 es 可能会超时,尽管根据文档,您应该预期会直接来自 es 的信息错误。您可以直接在 url 中设置 es 的超时 并对其进行测试。

希望这有帮助。

以上就是为什么 net/http 不考虑超过 30 秒的超时持续时间?的详细内容,更多请关注每日运维网(www.mryunwei.com)其它相关文章!

相关文章

JavaScript2024新功能:Object.groupBy、正则表达式v标志
PHP trim 函数对多字节字符的使用和限制
新函数 json_validate() 、randomizer 类扩展…20 个PHP 8.3 新特性全面解析
使用HTMX为WordPress增效:如何在不使用复杂框架的情况下增强平台功能
为React 19做准备:WordPress 6.6用户指南
如何删除WordPress中的所有评论

发布评论