前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >为什么使用 golang http包 会把 linux 句柄打满?

为什么使用 golang http包 会把 linux 句柄打满?

作者头像
阿兵云原生
发布2023-02-16 11:36:49
9810
发布2023-02-16 11:36:49
举报
文章被收录于专栏:golang云原生new

最近工作的时候一个接入服务需要测性能测试,万万没想到测出了一个把 linux 句柄打满的问题

具体是什么问题呢,我们一起来看看

正常操作

项目中,有一些 http 请求是这样写的:

  • 请求 https 的地址,为了绕过 tls ,加上了 TLSClientConfig: &tls.Config{InsecureSkipVerify: true} 配置
  • 正常访问我们需要的请求的地址
  • 正常获取我们的期望的数据,正常解析
代码语言:javascript
复制
func main() {
 client := http.Client{
  Transport: &http.Transport{
   TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
  },
 }
 resp, err := client.Get("https://www.xxxxxx.com")
 if err != nil {
  fmt.Println("Get err : ", err)
  return
 }
 defer resp.Body.Close()
 body, err := ioutil.ReadAll(resp.Body)
 fmt.Println(string(body))
}

例如如下是访问百度的结果,没有什么毛病

代码语言:javascript
复制
t# go run main.go
<html>
<head>
        <script>
                location.replace(location.href.replace("https://","http://"));
        </script>
</head>
<body>
        <noscript><meta http-equiv="refresh" content="0;url=http://www.baidu.com/"></noscript>
</body>
</html>

发现问题

可是例如这样的请求代码拿去做性能测试的话,我们实际遇到的问题是,linux 句柄数被打满了

句柄数被打满了,简单的思考有如下 2 个初步的可能:

  • linux 句柄数设置过小
  • http 代码没有释放连接

我知道的有如下 3 种方式,可以修改 linux 的句柄数:

1、修改 /etc/profile

直接修改 /etc/profile , 在 该文件最后加上如下语句

代码语言:javascript
复制
ulimit -n 65535

这里举个例子,设置 65535 个句柄数

修改后 执行

代码语言:javascript
复制
 source /etc/profile

查看效果

代码语言:javascript
复制
ulimit -a

2、修改 limits.conf 文件

直接修改 limits.conf,让其生效

代码语言:javascript
复制
vim /etc/security/limits.conf

3、修改 login 文件

我们可以在 /etc/pam.d/login 文件中 添加最下面一行

代码语言:javascript
复制
 session   required   pam_limits.so

例如上面这样添加

上述 第2 和 第3 种方式,需要重新 ssh 进入到服务器,或者重启服务器才可生效

虽然我增大了 linux 句柄数,发现在性能测试中,只是测得可以稍微久一点了,可是最终还是连接数被打满,这是为什么呢?

仔细查看了代码,代码中也有关闭 http 的连接

那么问题会是处在哪里呢?

找到问题解决问题

仔细查看了代码,只有一个怀疑点了,那就是下面这句话

代码语言:javascript
复制
client := http.Client{
  Transport: &http.Transport{
   TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
  },
 }

最初开始使用这句话的时候,目的也只是为了绕过 tls ,并没有考虑太多,现在仔细看看 http.Transport 结构体里面的功能

代码语言:javascript
复制
type Transport struct {
 idleMu       sync.Mutex
 closeIdle    bool                                // user has requested to close all idle conns
 idleConn     map[connectMethodKey][]*persistConn // most recently used at end
 idleConnWait map[connectMethodKey]wantConnQueue  // waiting getConns
 idleLRU      connLRU

 reqMu       sync.Mutex
 reqCanceler map[cancelKey]func(error)

 altMu    sync.Mutex   // guards changing altProto only
 altProto atomic.Value // of nil or map[string]RoundTripper, key is URI scheme

 connsPerHostMu   sync.Mutex
 connsPerHost     map[connectMethodKey]int
 connsPerHostWait map[connectMethodKey]wantConnQueue // waiting getConns
    ...........省略多行   ...........
    
    // TLSClientConfig specifies the TLS configuration to use with
 // tls.Client.
 // If nil, the default configuration is used.
 // If non-nil, HTTP/2 support may not be enabled by default.
 TLSClientConfig *tls.Config

 // TLSHandshakeTimeout specifies the maximum amount of time waiting to
 // wait for a TLS handshake. Zero means no timeout.
 TLSHandshakeTimeout time.Duration

 // DisableKeepAlives, if true, disables HTTP keep-alives and
 // will only use the connection to the server for a single
 // HTTP request.
 //
 // This is unrelated to the similarly named TCP keep-alives.
 DisableKeepAlives bool
    ...........省略多行   ...........
    }

仔细查看了上述结构之后,发现 DisableKeepAlives 可以禁用长连接,,每个请求都会创建一个连接,切请求完就会马上关闭连接

正确设置 Transport 后问题得以解决

代码语言:javascript
复制
client := http.Client{
  Transport: &http.Transport{
   TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
   DisableKeepAlives: true,
  },
 }

该问题表象看上去是没有设置好 http.Transport

实际上是 go http 包对于连接的管理 我们还没有去熟悉他,对于他关于连接的具体实现和细节代码,日后有机会再分享

代码修改完毕,性能测试果然正常通过,对技术对代码一定要有敬畏之心

欢迎点赞,关注,收藏

朋友们,你的支持和鼓励,是我坚持分享,提高质量的动力

好了,本次就到这里

技术是开放的,我们的心态,更应是开放的。拥抱变化,向阳而生,努力向前行。

我是阿兵云原生,欢迎点赞关注收藏,下次见~

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-12-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 阿兵云原生 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 正常操作
  • 发现问题
    • 1、修改 /etc/profile
      • 2、修改 limits.conf 文件
        • 3、修改 login 文件
        • 找到问题解决问题
        • 欢迎点赞,关注,收藏
        相关产品与服务
        SSL 证书
        腾讯云 SSL 证书(SSL Certificates)为您提供 SSL 证书的申请、管理、部署等服务,为您提供一站式 HTTPS 解决方案。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档