返回介绍

超时原因

发布于 2024-10-12 12:11:02 字数 1422 浏览 0 评论 0 收藏 0

大家知道 HTTP 是应用层协议,传输层用的是 TCP 协议。

HTTP 协议从 1.0 以前,默认用的是短连接,每次发起请求都会建立 TCP 连接。收发数据。然后断开连接。

TCP 连接每次都是三次握手。每次断开都要四次挥手。

其实没必要每次都建立新连接,建立的连接不断开就好了,每次发送数据都复用就好了。

于是乎,HTTP 协议从 1.1 之后就默认使用长连接。具体相关信息可以看之前的 这篇文章

那么 golang 标准库里也兼容这种实现。

通过建立一个连接池,针对每个域名建立一个 TCP 长连接,比如 http://baidu.comhttp://golang.com 就是两个不同的域名。

第一次访问 http://baidu.com 域名的时候会建立一个连接,用完之后放到空闲连接池里,下次再要访问 http://baidu.com 的时候会重新从连接池里把这个连接捞出来复用。

img

复用长连接

为什么要强调是同一个域名:一个域名会建立一个连接,一个连接对应一个读 goroutine 和一个写 goroutine。正因为是同一个域名,所以最后才会泄漏 3 个 goroutine,如果不同域名的话,那就会泄漏 1+2*N 个协程,N 就是域名数。

假设第一次请求要 100ms,每次请求完 http://baidu.com 后都放入连接池中,下次继续复用,重复 29 次,耗时 2900ms。

第 30 次请求的时候,连接从建立开始到服务返回前就已经用了 3000ms,刚好到设置的 3s 超时阈值,那么此时客户端就会报超时 i/o timeout。

虽然这时候服务端其实才花了 100ms,但耐不住前面 29 次加起来的耗时已经很长。

也就是说只要通过 http.Transport 设置了 err = conn.SetDeadline(time.Now().Add(time.Second * 3)) ,并且用了长连接,哪怕服务端处理再快,客户端设置的超时再长,总有一刻,程序会报超时错误。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文