gin

gin启动和请求流程,压测

Posted by Liangjf on June 29, 2019

gin启动和请求流程,压测

分析

new一个Engine代表gin服务

g := gin.Default()

gin启动

g.Run

http监听服务

http.ListenAndServe

server监听服务

server.ListenAndServe()

监听连接

ln, err := net.Listen("tcp", addr)
return srv.Serve(tcpKeepAliveListener{ln.(*net.TCPListener)})

等待客户端链接

rw, e := l.Accept()

new一个客户端并go一条groutine来处理当前请求

c := srv.newConn(rw)
go c.serve(ctx)

读请求内容,处理请求

w, err := c.readRequest(ctx)
serverHandler{c.server}.ServeHTTP(w, w.req)

serverHandler调用ServeHTTP处理当前请求

func (sh serverHandler) ServeHTTP(rw ResponseWriter, req *Request)

  • handler.ServeHTTP

获得路由对应的handler调用ServeHTTP来处理当前的请求

func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request)

  • h, _ := mux.Handler(r)
  • h.ServeHTTP(w, r)

获得路由对应的handler和pattern

handler.ServeHTTP(rw, req)

  • ServeMux实现了Handler方法,所以会调用到(mux* ServeMux) Handler
  • var DefaultServeMux = &defaultServeMux
  • var defaultServeMux ServeMux
  • func (mux* ServeMux) Handler(r* Request) (h Handler, pattern string)
    • mux.handler(host, r.URL.Path)
      • h, pattern = mux.match
        • 匹配路由对应的handler

真正的路由响应函数调用

func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) { f(w, r) }

思路

通过注册路由和handle函数到路由表中,路由表构建一棵tree。然后就启动listen和accept,有新连接来就new一个conn对象代表当前连接,然后go一条协程单独处理当前请求。接着通过serverHandler和ServeMux实现的ServeHTTP解析路由匹配到handle和pattern,最后通过得到的handler调用真正的路有响应函数处理请求。主要借助了结构体和接口的形式,层层封装代理,直至到在最后的处理响应。

总结

gin就是一个轻量级,高效,方便的web 框架,更偏向于应用服务。

压测gin

附带gin的压测

wrk -c 100 -t 10 -d 10m http://172.16.1.11:8090/hello

  • 开10条线程,100并发。

电脑配置

  • 双核 Intel® Core™ i5-4210M CPU @ 2.60GHz
  • 8.1 GB 内存
package main

import (
    "fmt"
    "github.com/gin-gonic/gin"
)

func main() {
    g := gin.Default()

    g.GET("/hello", func(context *gin.Context) {
        context.JSON(200, gin.H{
            "hello":1,
        })
    })

    fmt.Println(g.Run(":8090").Error())
}

结果:

Running 10m test @ http://172.16.1.11:8090/hello
  10 threads and 100 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    14.77ms   20.79ms 119.25ms   82.05%
    Req/Sec     1.95k   538.61     5.05k    68.19%
  2930271 requests in 2.61m, 377.26MB read
  Socket errors: connect 0, read 143, write 765925, timeout 0
Requests/sec:  18692.82
Transfer/sec:      2.41MB

Running 10m test @ http://172.16.1.11:8090/hello
  10 threads and 100 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     8.67ms   13.81ms  96.16ms   88.72%
    Req/Sec     2.67k   694.90     5.72k    67.32%
  836443 requests in 31.45s, 107.69MB read
Requests/sec:  26599.34
Transfer/sec:      3.42MB

看压测结果,gin上万qps是比较轻松的。