美文网首页
GO HTTP1.1 与 HTTP2.0 的使用和简单分析

GO HTTP1.1 与 HTTP2.0 的使用和简单分析

作者: sarto | 来源:发表于2020-09-23 17:54 被阅读0次

HTTP1.1

服务端

func RunH1Server(l net.Listener) {
    svr := &http.Server{
        Handler: &HTTPServer{},
    }
    svr.SetKeepAlivesEnabled(true)
    svr.Serve(l)
}


func (s *HTTPServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    //fmt.Println(r.Header.Get("User-Agent"))
    time.Sleep(10 * time.Millisecond)
    w.WriteHeader(http.StatusOK)
}

客户端

func getH1Client() *http.Client {
    return &http.Client{
        Transport: &http.Transport{
            DisableKeepAlives:   false,
            DisableCompression:  false,
            MaxIdleConns:        100,
            MaxIdleConnsPerHost: 100,
            MaxConnsPerHost:     100,
        },
    }
}

Benchmark 测试

func runHTTP1P(b *testing.B, num int) {
    l, _ := net.Listen("tcp", url)
    go RunH1Server(l)
    defer l.Close()

    c := getH1Client()

    runtime.GOMAXPROCS(num)
    b.ReportAllocs()
    b.StartTimer()
    b.RunParallel(func(pb *testing.PB) {
        for pb.Next() {
            resp, err := c.Get("http://" + url)
            if err != nil {
                panic(err)
            }
            ioutil.ReadAll(resp.Body)
            resp.Body.Close()
        }
    })
}

func BenchmarkH1HTTP_1(b *testing.B) {
    runHTTP1P(b, 1)
}
func BenchmarkH1HTTP_10(b *testing.B) {
    runHTTP1P(b, 10)
}
func BenchmarkH1HTTP_100(b *testing.B) {
    runHTTP1P(b, 100)
}
func BenchmarkH1HTTP_1000(b *testing.B) {
    runHTTP1P(b, 1000)
}

测试结果

> go test -v http1.1_test.go -bench=.
goos: windows
goarch: amd64
pkg: github.com/bemyth/go-language-advanced
BenchmarkH1HTTP_1
BenchmarkH1HTTP_1-16             118      10034472 ns/op        4838 B/op         52 allocs/op

BenchmarkH1HTTP_10
BenchmarkH1HTTP_10-16           1174       1009868 ns/op        4862 B/op         51 allocs/op

BenchmarkH1HTTP_100
BenchmarkH1HTTP_100-16         11458        101681 ns/op        4994 B/op         51 allocs/op

BenchmarkH1HTTP_200
BenchmarkH1HTTP_200-16         11628        102002 ns/op        4981 B/op         52 allocs/op

BenchmarkH1HTTP_1000
BenchmarkH1HTTP_1000-16        11418        102651 ns/op        5126 B/op         53 allocs/op
PASS

我们设定服务端处理一次请求需要 10 ms,我们可以得到三个信息

  • 根据测试1,单个连接在 1s 内可以执行 100 次请求,符合预期
  • 根据测试1,2,3,我们依次增大并行度,单位时间内(1s)内的处理效率与并行度等比例上升
  • 根据测试3,4,5由于连接池限制最大为100,即使并行度增加,处理效率也并无提升

所以我们可以得到结论,对于一个稳定的服务器,HTTP1.1 单位时间的处理效率和连接数成正比,需要更高的处理效率就必须不断的增加 TCP 连接。因为 HTTP1.1 的请求遵循 FIFO。

HTTP2.0

服务端

func RunH2Server(l net.Listener) {
    svr := &HTTPServer{}

    s2 := &http2.Server{}

    s1 := http.Server{
        TLSConfig: &tls.Config{
            InsecureSkipVerify: true,
        },
        Handler: h2c.NewHandler(svr, s2),
    }
    s1.Serve(l)
}

func (s *HTTPServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    //fmt.Println(r.Header.Get("User-Agent"))
    time.Sleep(10 * time.Millisecond)
    w.WriteHeader(http.StatusOK)
}

客户端

func getH2Client() *http.Client {
    return &http.Client{
        Transport: &http2.Transport{
            DialTLS: func(network, addr string, cfg *tls.Config) (net.Conn, error) {
                return net.Dial(network, addr)
            },
            AllowHTTP: true,
        },
        CheckRedirect: nil,
        Jar:           nil,
        Timeout:       0,
    }
}

Benchmark 测试

func runHTTP2P(b *testing.B, num int) {
    l, _ := net.Listen("tcp", url)
    go RunH2Server(l)
    defer l.Close()

    c := getH2Client()

    runtime.GOMAXPROCS(num)
    b.ReportAllocs()
    b.StartTimer()
    b.RunParallel(func(pb *testing.PB) {
        for pb.Next() {
            resp, err := c.Get("http://" + url)
            if err != nil {
                panic(err)
            }
            ioutil.ReadAll(resp.Body)
            resp.Body.Close()
        }
    })
}
func BenchmarkH2HTTP_1(b *testing.B) {
    runHTTP2P(b, 1)
}
func BenchmarkH2HTTP_10(b *testing.B) {
    runHTTP2P(b, 10)
}
func BenchmarkH2HTTP_100(b *testing.B) {
    runHTTP2P(b, 100)
}
func BenchmarkH2HTTP_200(b *testing.B) {
    runHTTP2P(b, 200)
}
func BenchmarkH2HTTP_1000(b *testing.B) {
    runHTTP2P(b, 1000)
}

测试结果

> go test -v http2.0_test.go -bench=.

goos: windows
goarch: amd64
pkg: github.com/bemyth/go-language-advanced
BenchmarkH2HTTP_1
testing: BenchmarkH2HTTP_1-16 left GOMAXPROCS set to 1
BenchmarkH2HTTP_1-16             118      10034539 ns/op        6012 B/op         65 allocs/op

BenchmarkH2HTTP_10
testing: BenchmarkH2HTTP_10-16 left GOMAXPROCS set to 10
BenchmarkH2HTTP_10-16           1186       1005127 ns/op        5843 B/op         63 allocs/op

BenchmarkH2HTTP_100
BenchmarkH2HTTP_100-16         11799        101626 ns/op        6001 B/op         63 allocs/op

BenchmarkH2HTTP_200
BenchmarkH2HTTP_200-16         22471         52694 ns/op        6016 B/op         63 allocs/op

BenchmarkH2HTTP_1000
BenchmarkH2HTTP_1000-16         7792        155429 ns/op        6721 B/op         66 allocs/op
testing: BenchmarkH2HTTP_1000-16 left GOMAXPROCS set to 1000
PASS

GO HTTP2.0 我没有找到设置连接池数量的地方,但是在测试中执行

netstat -an|find "8080"

发现连接数量一直是 4 个,同时我们可以看到,仅仅 4 个 TCP 连接,就能在并发达到 200 的时候 1s 内执行 2w 次请求。效率远超 HTTP1.1,且不需要更多的 TCP 连接。

相关文章

网友评论

      本文标题:GO HTTP1.1 与 HTTP2.0 的使用和简单分析

      本文链接:https://www.haomeiwen.com/subject/oqvoyktx.html