返回介绍

排查

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

img

五层网络协议对应的消息体变化分析

就很奇怪了,明明服务端显示处理耗时才 100ms,且客户端超时设的是 3s, 怎么就出现超时报错 i/o timeout 呢?

这里推测有两个可能。

  • 因为服务端打印的日志其实只是服务端应用层打印的日志。但客户端应用层发出数据后,中间还经过客户端的传输层,网络层,数据链路层和物理层,再经过服务端的物理层,数据链路层,网络层,传输层到服务端的应用层。服务端应用层处耗时 100ms,再原路返回。那剩下的 3s-100ms 可能是耗在了整个流程里的各个层上。比如网络不好的情况下,传输层 TCP 使劲丢包重传之类的原因。
  • 网络没问题,客户端到服务端链路整个收发流程大概耗时就是 100ms 左右。客户端处理逻辑问题导致超时。

一般遇到问题,大部分情况下都不会是底层网络的问题,大胆怀疑是自己的问题就对了,不死心就抓个包看下。

img

抓包结果

分析下,从刚开始三次握手(画了红框的地方)。

到最后出现超时报错 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 技术交流群。

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

发布评论

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