Go http client 连接池不复用的问题

本文探讨了Go http client在只读取response header而不读取body时,连接无法复用的问题。这种情况会导致连接被主动关闭,影响连接池效率。通过分析源码,发现是由于未读取body导致的earlyCloseFn回调,使得连接无法被复用。解决方案是确保读取完整个响应body。
摘要由CSDN通过智能技术生成

当 http client 返回值为不为空,只读取 response header,但不读 body 内容就执行 response.Body.Close(),那么连接会被主动关闭,得不到复用。

测试代码如下:

// xiaorui.cc

func HttpGet() {
 for {
  fmt.Println("new")
  resp, err := http.Get("http://www.baidu.com")
  if err != nil {
   fmt.Println(err)
   continue
  }

  if resp.StatusCode == http.StatusOK {
   continue
  }

  resp.Body.Close()
    
  fmt.Println("go num", runtime.NumGoroutine())
 }
}

正如大家所想,除了 HEAD Method 外,很少会有只读取 header 的需求吧。

话说,golang httpclient 需要注意的地方着实不少。

  • 如没有 response.Body.Close(),有些小场景造成 persistConn 的 writeLoop 泄露。

  • 如 header 和 body 都不管,那么会造成泄露的连接干满连接池,后面的请求只能是短连接

上下文

由于某几个业务系统会疯狂调用各区域不同的 k8s 集群,为减少跨机房带来的时延、兼容新老 k8s 集群 api、减少k8s api-server 的负载,故而开发了 k8scache 服务。在部署运行后开始对该服务进行监控,发现 metrics 呈现的 QPS 跟连接数不成正比,qps 为 1500,连接数为 10 个。开始以为触发 idle timeout 被回收,但通过历史监控图分析到连接依然很少。????

按照对 k8scache 调用方的理解,他们经常粗暴的开启不少协程来对 k8scache 进行访问。已知默认的 golang httpclient transport 对连接数是有默认限制的,连接池总大小为 100,每个 host 连接数为 2。当并发对某 url 进行请求时,无法归还连接池,也就是超过连接池大小的连接会被主动clsoe()。所以,我司的 golang 脚手架中会对默认的 httpclient 创建高配的 transport,不太可能出现连接池爆满被 close 的问题。

如果真的是连接池爆了?  谁主动挑起关闭,谁就有 tcp time-wait 状态,但通过 netstat 命令只发现少量跟 k8scache 相关的 time-wait。

排查问题

已知问题,  为隐藏敏感信息,索性使用简单的场景设立问题的 case

tcpdump抓包分析问题?

包信息如下,通过最后一行可以确认是由客户端主动触发 RST连接重置 。触发RST的场景有很多,但常见的有 tw_bucket 满了、tcp 连接队列爆满且开启 tcp_abort_on_overflow、配置 so_linger、读缓冲区还有数据就给 close。

通过 linux 监控和内核日志可以确认不是内核配置的问题,配置 so_linger 更不可能。???? 大概率就一个可能,关闭未清空读缓冲区的连接。

22:11:01.790573 IP (tos 0x0, ttl 64, id 29826, offset 0, flags [DF], proto TCP (6), length 60)
    host-46.54550 > 110.242.68.3.http: Flags [S], cksum 0x5f62 (incorrect -> 0xb894), seq 1633933317, win 29200, options [mss 1460,sackOK,TS val 47230087 ecr 0,nop,wscale 7], length 0
22:11:01.801715 IP (tos 0x0, ttl 43, id 0, offset 0, flags [DF], proto TCP (6), length 52)
    110.242.68.3.http > host-46.54550: Flags [S.], cksum 0x00a0 (correct), seq 1871454056, ack 1633933318, win 29040, options [mss 1452,nop,nop,sackOK,nop,wscale 7], length 0
22:11:01.801757 IP (tos 0x0, ttl 64, id 29827, offset 0, flags [DF], proto TCP (6), length 40)
    host-46.54550 > 110.242.68.3.http: Flags [.], cksum 0x5f4e (in
  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值