net/http: TLS handshake timeout 问题

最近系统偶现”net/http: TLS handshake timeout“,而且都集中在同一个机房,这个报错还是第一次见,产生的原因和解决的方案都比较有意思。

现场

报错的信息为:

 

vbscript

代码解读

复制代码

Error sending request:%!(EXTRA *url.Error=Get "https://****//test_image.jpg?lk3s=50ccb0c5&x-expires=1733490979%3D": net/http: TLS handshake timeout)

报错的位置为resp, err := client.Do(req):

 

go

代码解读

复制代码

func GetImageContent(ctx context.Context, imageURL string) (string, oc_error.Error) { // Create an HTTP client client := &http.Client{} // Create a new request using http req, err := http.NewRequest("GET", imageURL, nil) if err != nil { logs.CtxError(ctx, "Error creating request:", err) return "", config.SystemError } // Send the request via a client resp, err := client.Do(req) if err != nil { logs.CtxError(ctx, "Error sending request:", err) return "", config.SystemError } defer resp.Body.Close() // Check if the request was successful if resp.StatusCode != http.StatusOK { logs.CtxError(ctx, "Error: Non-200 HTTP status code:", err) return "", config.SystemError } body, err := ioutil.ReadAll(resp.Body) if err != nil { logs.CtxError(ctx, "ReadAll error %+v", err) return "", config.SystemError } return string(body), nil }

线索

通过查看日志,发现从请求开始到报错,经历了10s。为什么是10s呢?net/http包的默认TLSHandshakeTimeout超时时间是10s。

 

go

代码解读

复制代码

// DefaultTransport is the default implementation of Transport and is // used by DefaultClient. It establishes network connections as needed // and caches them for reuse by subsequent calls. It uses HTTP proxies // as directed by the environment variables HTTP_PROXY, HTTPS_PROXY // and NO_PROXY (or the lowercase versions thereof). var DefaultTransport RoundTripper = &Transport{ Proxy: ProxyFromEnvironment, DialContext: defaultTransportDialContext(&net.Dialer{ Timeout: 30 * time.Second, KeepAlive: 30 * time.Second, }), ForceAttemptHTTP2: true, MaxIdleConns: 100, IdleConnTimeout: 90 * time.Second, TLSHandshakeTimeout: 10 * time.Second, ExpectContinueTimeout: 1 * time.Second, }

大家一般不配置,但如果想配置的话,可以这么写

 

go

代码解读

复制代码

c := &http.Client{ Transport: &Transport{ Dial: (&net.Dialer{ Timeout: 30 * time.Second, KeepAlive: 30 * time.Second, }).Dial, TLSHandshakeTimeout: 10 * time.Second, ResponseHeaderTimeout: 10 * time.Second, ExpectContinueTimeout: 1 * time.Second, } }

TLS handshake过程

以前写过HTTPS连接过程,这里面详细描述了TLS的执行过程。TLS过程中,发送端和接收端都需要给双方提供一些信息,当然也需要用到证书。

所以产生的原因可能有三处,一个是运行我程序的容器有问题(可能性比较小),一个是网络(内部网络或外部网络)上有问题(可能性比较大)。

先去找了容器的同学,他们反馈最近没有更新,而且感觉真的是容器的问题,大概率是百分百出问题。

然后去找CDN的同学,初步判断是外部网络的问题。

追查

其实这个机房报错概率还是比较高的,在5%~10%之间。

找问题IP

为了完整复现,登录容器,执行

 

shell

代码解读

复制代码

curl -v https://****

使用 curl --verbose或curl -v 命令可以详细显示 HTTP 请求和响应的过程

我们的域名对应多个IP地址,多次执行curl,发现部分IP地址确实会慢。

抓包

开两个窗口,一个窗口执行如下命令,使用tcpdump抓包,其中的ip是上面查到的有问题的ip,将抓包结果写入指定文件

 

arduino

代码解读

复制代码

tcpdump -i any host ip1 or host ip2 or ip3 -w /home/if9.pcap

开另一个窗口,执行curl,一直执行到对应的ip确实出现握手失败的时候。

导出数据

把容器里的文件下载到本地,超复杂,但公司的同学真的是什么都经历过了,愣是走出了一条路。

需要使用item2,配置sz指令,

下载好抓到的包,可以使用WireShark进行分析,你看,10s的位置就找到了。

解决

后续CDN的同学找了厂商,根据厂商反馈是厂商节点问题,对应的节点性能有点减弱,从服务链路进行剔除。针对全网是否还有类似的节点,厂商继续全网检查看看,有类似的及时处理掉。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值