文章来源于网络收集而来,版权归原创者所有,如有侵权请及时联系!
排查
五层网络协议对应的消息体变化分析
就很奇怪了,明明服务端显示处理耗时才 100ms,且客户端超时设的是 3s, 怎么就出现超时报错 i/o timeout 呢?
这里推测有两个可能。
- 因为服务端打印的日志其实只是服务端应用层打印的日志。但客户端应用层发出数据后,中间还经过客户端的传输层,网络层,数据链路层和物理层,再经过服务端的物理层,数据链路层,网络层,传输层到服务端的应用层。服务端应用层处耗时 100ms,再原路返回。那剩下的 3s-100ms 可能是耗在了整个流程里的各个层上。比如网络不好的情况下,传输层 TCP 使劲丢包重传之类的原因。
- 网络没问题,客户端到服务端链路整个收发流程大概耗时就是 100ms 左右。客户端处理逻辑问题导致超时。
一般遇到问题,大部分情况下都不会是底层网络的问题,大胆怀疑是自己的问题就对了,不死心就抓个包看下。
抓包结果
分析下,从刚开始三次握手(画了红框的地方)。
到最后出现超时报错 i/o timeout(画了蓝框的地方)。
从 time 那一列从 7 到 10,确实间隔 3s。而且看右下角的蓝框,是 51169 端口发到 80 端口的一次 Reset 连接。
80 端口是服务端的端口。换句话说就是客户端 3s 超时主动断开链接的。
但是再仔细看下第一行三次握手到最后客户端超时主动断开连接的中间,其实有非常多次 HTTP 请求。
回去看代码设置超时的方式。
tr = &http.Transport{
MaxIdleConns: 100,
Dial: func(netw, addr string) (net.Conn, error) {
conn, err := net.DialTimeout(netw, addr, time.Second*2) //设置建立连接超时
if err != nil {
return nil, err
}
err = conn.SetDeadline(time.Now().Add(time.Second * 3)) //设置发送接受数据超时
if err != nil {
return nil, err
}
return conn, nil
},
}
也就是说,这里的 3s 超时,其实是在建立连接之后开始算的,而不是单次调用开始算的超时。
看注释里写的是
SetDeadline sets the read and write deadlines associated with theconnection.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论