go的net/http有哪些值得关注的细节? 3

简介: go的net/http有哪些值得关注的细节?
+关注继续查看

连接池的结构

我们了解到连接池可以复用网络连接,接下来我们通过一个例子来看看网络连接池的结构。

func main() {
    tr := &http.Transport{
        MaxIdleConns:    100,
        IdleConnTimeout: 3 * time.Second,
    }
    n := 5
    for i := 0; i < n; i++ {
        req, _ := http.NewRequest("POST", "http://www.baidu.com", nil)
        req.Header.Add("content-type", "application/json")
        client := &http.Client{
            Transport: tr,
            Timeout:   3 * time.Second,
        }
        resp, _ := client.Do(req)
        _, _ = ioutil.ReadAll(resp.Body)
        _ = resp.Body.Close()
    }
    time.Sleep(time.Second * 1)
    fmt.Printf("goroutine num is %d\n", runtime.NumGoroutine())
}

注意这里请求的不是https,而是http。最终结果输出5,为什么?

这是因为,http://www.baidu.com会返回307,重定向到https://www.baidu.com

image

http重定向为https

在网络中,我们可以通过一个五元组来唯一确定一个TCP连接。

image

五元组

它们分别是源ip,源端口,协议,目的ip,目的端口。只有当多次请求的五元组一样的情况下,才有可能复用连接。

放在我们这个场景下,源ip、源端口、协议都是确定的,也就是两次http请求的目的ip或目的端口有区别的时候,就需要使用不同的TCP长连接。

而http用的是80端口,https用的是443端口。于是连接池就为不同的网络目的地建立不同的长连接。

因此最终结果5个goroutine,其实2个goroutine来自http,2个goroutine来自https,1个main goroutine。

我们来看下源码的具体实现。net/http底层通过一个叫idleConnmap去存空闲连接,也就是空闲连接池。

imageimage


idleConn这个map的key是协议和地址,其实本质上就是ip和端口。map的value是长连接的数组([]*persistConn),说明net/http支持为同一个地址建立多个TCP连接,这样可以提升传输的吞吐。

image

连接池的结构和逻辑


Transport是什么?

Transport本质上是一个用来控制http调用行为的一个组件,里面包含超时控制,连接池等,其中最重要的是连接池相关的配置。

我们通过下面的例子感受下。

func main() {
    n := 5
    for i := 0; i < n; i++ {
        httpClient := &http.Client{}
        resp, _ := httpClient.Get("https://www.baidu.com")
        _, _ = ioutil.ReadAll(resp.Body)
        _ = resp.Body.Close()
    }
    time.Sleep(time.Second * 1)
    fmt.Printf("goroutine num is %d\n", runtime.NumGoroutine())
}
func main() {
    n := 5
    for i := 0; i < n; i++ {
        httpClient := &http.Client{
            Transport:  &http.Transport{},
        }
        resp, _ := httpClient.Get("https://www.baidu.com")
        _, _ = ioutil.ReadAll(resp.Body)
        _ = resp.Body.Close()
    }
    time.Sleep(time.Second * 1)
    fmt.Printf("goroutine num is %d\n", runtime.NumGoroutine())
}

上面的代码第一个例子的代码会输出3。分别是main goroutine + read goroutine + write goroutine,也就是有一个被不断复用的TCP连接。

在第二例子中,当我们在每次client中都创建一个新的http.Transport,此时就会输出11

说明TCP连接没有复用,每次请求都会产生新的连接。这是因为每个http.Transport内都会维护一个自己的空闲连接池,如果每个client都创建一个新的http.Transport,就会导致底层的TCP连接无法复用。如果网络请求过大,上面这种情况会导致协程数量变得非常多,导致服务不稳定。

因此,最佳实践是所有client都共用一个transport

func main() {
    tr := &http.Transport{
        MaxIdleConns:    100,
        IdleConnTimeout: 3 * time.Second,
    }
    n := 5
    for i := 0; i < n; i++ {
        req, _ := http.NewRequest("POST", "https://www.baidu.com", nil)
        req.Header.Add("content-type", "application/json")
        client := &http.Client{
            Transport: tr,
            Timeout:   3 * time.Second,
        }
        resp, _ := client.Do(req)
        _, _ = ioutil.ReadAll(resp.Body)
        _ = resp.Body.Close()
    }
    time.Sleep(time.Second * 1)
    fmt.Printf("goroutine num is %d\n", runtime.NumGoroutine())
}

如果创建客户端的时候不指定http.Client,会默认所有http.Client都共用同一个DefaultTransport。这一点可以从源码里看出。

image

默认使用DefaultTransportimage

DefaultTransport

因此当第二段代码中,每次都重新创建一个Transport的时候,每个Transport内都会各自维护一个空闲连接池。因此每次建立长连接后都会多两个协程(读+写),对应1个main goroutine+(read goroutine + write goroutine)* 5 =11。

目录
相关文章
|
10天前
|
安全 网络协议 Go
GO 中如何设置 HTTPS 分享
GO 中如何设置 HTTPS 分享
|
21天前
|
SQL 开发框架 前端开发
Go标准库http/template
Go标准库http/template
25 0
|
2月前
|
Go 数据库 微服务
Go语言微服务框架 - 1.搭建gRPC+HTTP的双重网关服务
大家好,我是六月天天。如题所述,从今天开始,我将和大家一起逐步完成一个微服务框架。
24 1
|
2月前
|
Go
Go 使用标准库 net/http 包构建服务器
Go 使用标准库 net/http 包构建服务器
11 0
|
4月前
|
网络协议 Go
go的net/http有哪些值得关注的细节? 4
go的net/http有哪些值得关注的细节?
55 0
|
4月前
|
Go
go的net/http有哪些值得关注的细节? 2
go的net/http有哪些值得关注的细节?
40 0
|
4月前
|
网络协议 Go
go的net/http有哪些值得关注的细节? 1
go的net/http有哪些值得关注的细节?
36 0
|
10月前
|
编解码 JSON 负载均衡
rpc的正确打开方式|读懂Go原生net/rpc包
我希望借助这篇文章,用尽可能少的语言,配合分析Go原生net/rpc包的部分核心代码,帮助你贯通RPC的知识,梳理RPC的运作流程,让你对RPC有一个比较全面的认识。
127 0
rpc的正确打开方式|读懂Go原生net/rpc包
|
11月前
|
网络协议 Go 数据安全/隐私保护
|
存储 Go 网络架构
Go HTTP 编程 | 02 - net/http 包剖析
Go HTTP 编程 | 02 - net/http 包剖析
Go HTTP 编程 | 02 - net/http 包剖析
相关产品
云迁移中心
推荐文章
更多