测试目的

由于K8s缘故涉猎go语言,发现golang的web框架很多,都号称高性能标杆;之前一直致力于c++高性能服务端框架研究,出于好奇,想单从性能层面客观比较一下go的众多web框架,另一方面也希望看看c++的实现与go语言实现之间究竟存在多大差异。

高性能服务框架评估指标很多,但一般来讲吞吐量与QPS是关键考量指标,吞吐量衡量带宽利用率,QPS主要考验框架调度性能(几乎所有可称之为“高性能”的服务框架都没有吞吐量问题,毕竟网络瓶颈很轻易就达到了)。由于是框架本身QPS测试,为了屏蔽http协议实现差异选择最精简的协议头(协议处理一般不会有锁,为cpu密集型),因此要求请求/返回报文尽可能小,本文测试基于http协议,返回空报文。

为了实现测试的第二个目的,特将一个自撸的c++服务框架作为c++实现的”砖头”,加入到对比测试中。此框架尚未开源,其高性能特性保障体现在如下设计上:

跨平台实现socket多路复用,支持:poll、epoll、kqueue、port、select、IOCP等模型

采用lock-free算法

线程池设计

socket连接池

多级任务队列

……

PS:

好吧,这样一来貌似更接近测试socket服务框架调度性能……

不要纠结keep-alive,因为wrk使用HTTP/1.1,默认都是keep-alive的

测试环境

57de60ea1a7eedf72583d778aefc132d.png

env.jpg

环境设置

ulimit -n 2000

压测工具

wrk

由于环境限制,只能wrk客户端和待测试服务端在一台机器上运行

c++自研框架

启动脚本:(最大2000个并发连接,2个线程处理,http端口8080)

./proxy_server -i2000 -o2000 -w2 -x8080

http返回报文:

$ curl -i http://localhost:8080/

HTTP/1.1 200 OK

Content-Length: 0

Connection: keep-alive

压测结果:

$wrk -d 100s -c 1024 -t 8 http://localhost:8080/

Running 2m test @ http://localhost:8080/

8 threads and 1024 connections

Thread Stats Avg Stdev Max +/- Stdev

Latency 13.03ms 3.80ms 100.73ms 86.97%

Req/Sec 9.43k 1.64k 39.35k 88.23%

7509655 requests in 1.67m, 444.03MB read

Socket errors: connect 0, read 794, write 2, timeout 0

Requests/sec: 75018.11

Transfer/sec: 4.44MB

资源占用:

fd9f8c87038180484abbda663b5d9b68.png

proxy_server.jpg

go-restful框架:

main_go-restful.go

package main

import (

"github.com/emicklei/go-restful"

"net/http"

)

func main(){

ws := new(restful.WebService)

ws.Route(ws.GET("/").To(hello))

restful.Add(ws)

http.ListenAndServe(":8080",nil)

}

func hello(req *restful.Request,resp *restful.Response){

resp.Write([]byte(""))

}

http返回报文:

$curl -i http://localhost:8080/

HTTP/1.1 200 OK

Date: Mon, 21 Oct 2019 03:54:27 GMT

Content-Length: 0

压测结果:

$wrk -d 100s -c 1024 -t 8 http://localhost:8080/

Running 2m test @ http://localhost:8080/

8 threads and 1024 connections

Thread Stats Avg Stdev Max +/- Stdev

Latency 19.72ms 10.57ms 331.94ms 87.67%

Req/Sec 6.52k 1.24k 23.75k 80.42%

5180908 requests in 1.67m, 370.57MB read

Socket errors: connect 0, read 844, write 3, timeout 0

Requests/sec: 51757.61

Transfer/sec: 3.70MB

资源占用:

979d0a19083641af85f002f7633f7220.png

go-restful.jpg

go-echo框架:

main_go-echo.go

package main

import (

"net/http"

"github.com/labstack/echo"

)

func main() {

e := echo.New()

e.GET("/", func(c echo.Context) error {

return c.String(http.StatusOK, "")

})

e.Logger.Fatal(e.Start(":8080"))

}

http返回报文:

$ curl -i http://localhost:8080/

HTTP/1.1 200 OK

Content-Type: text/plain; charset=UTF-8

Date: Mon, 21 Oct 2019 04:09:24 GMT

Content-Length: 0

压测结果:

$ wrk -d 100s -c 1024 -t 8 http://localhost:8080/

Running 2m test @ http://localhost:8080/

8 threads and 1024 connections

Thread Stats Avg Stdev Max +/- Stdev

Latency 17.32ms 8.19ms 252.60ms 90.70%

Req/Sec 7.52k 1.35k 39.96k 80.55%

5974370 requests in 1.67m, 660.92MB read

Socket errors: connect 0, read 431, write 67, timeout 0

Requests/sec: 59686.09

Transfer/sec: 6.60MB

资源占用:

712f2d6e96757c181253007e49ee7fa4.png

go-echo.jpg

go-iris框架:

main_go-iris.go

package main

import(

"time"

"github.com/kataras/iris"

"github.com/kataras/iris/cache"

)

func main(){

app := iris.New()

app.Logger().SetLevel("error")

app.Get("/",cache.Handler(10*time.Second),writeMarkdown)

app.Run(iris.Addr(":8080"))

}

func writeMarkdown(ctx iris.Context){

ctx.Markdown([]byte(""))

}

http返回报文:

$ curl -i http://localhost:8080/

HTTP/1.1 200 OK

Content-Type: text/html; charset=UTF-8

Date: Mon, 21 Oct 2019 04:11:59 GMT

Content-Length: 0

压测结果:

$ wrk -d 100s -c 1024 -t 8 http://localhost:8080/

Running 2m test @ http://localhost:8080/

8 threads and 1024 connections

Thread Stats Avg Stdev Max +/- Stdev

Latency 22.03ms 7.99ms 140.47ms 84.58%

Req/Sec 5.79k 775.23 19.31k 80.35%

4608572 requests in 1.67m, 505.43MB read

Socket errors: connect 0, read 726, write 22, timeout 0

Requests/sec: 46041.23

Transfer/sec: 5.05MB

资源占用:

867067c165de2ced3bcf1d68b035aeac.png

go-iris.jpg

go-gin框架

main_go-gin.go

package main

import (

"fmt"

"net/http"

"log"

"github.com/julienschmidt/httprouter"

)

func Index(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {

fmt.Fprint(w, "")

}

func main() {

router := httprouter.New()

router.GET("/", Index)

log.Fatal(http.ListenAndServe(":8080", router))

}

http返回报文:

$ curl -i http://localhost:8080/

HTTP/1.1 200 OK

Date: Mon, 21 Oct 2019 04:15:33 GMT

Content-Length: 0

压测结果:

$ wrk -d 100s -c 1024 -t 8 http://localhost:8080/

Running 2m test @ http://localhost:8080/

8 threads and 1024 connections

Thread Stats Avg Stdev Max +/- Stdev

Latency 16.71ms 7.72ms 268.45ms 87.79%

Req/Sec 7.71k 1.58k 21.27k 82.12%

6130281 requests in 1.67m, 438.47MB read

Socket errors: connect 0, read 693, write 36, timeout 0

Requests/sec: 61243.74

Transfer/sec: 4.38MB

资源占用:

d431db6d0c0d2dcdc73b7cb60ecf6e74.png

go-gin.jpg

go-chi框架:

main_go-chi.go

package main

import (

"net/http"

"github.com/go-chi/chi"

)

func main() {

r := chi.NewRouter()

r.Get("/", func(w http.ResponseWriter, r *http.Request) {

w.Write([]byte(""))

})

http.ListenAndServe(":8080", r)

}

http返回报文:

$ curl -i http://localhost:8080/

HTTP/1.1 200 OK

Date: Mon, 21 Oct 2019 04:18:42 GMT

Content-Length: 0

压测结果:

$ wrk -d 100s -c 1024 -t 8 http://localhost:8080/

Running 2m test @ http://localhost:8080/

8 threads and 1024 connections

Thread Stats Avg Stdev Max +/- Stdev

Latency 17.17ms 8.47ms 253.47ms 90.07%

Req/Sec 7.65k 1.42k 26.08k 79.76%

6071695 requests in 1.67m, 434.28MB read

Socket errors: connect 0, read 110, write 2, timeout 0

Requests/sec: 60658.49

Transfer/sec: 4.34MB

资源占用:

11e0c416fca723abeda1385cc95739c1.png

go-chi.jpg

结论:

-

cpu-free

mem-usage

qps

c++

15%-20%

6M

75018.11

go-gin

0%-1.5%

28M

61243.74

go-chi

0%-1%

28M

60658.49

go-echo

0%-0.5%

28M

59686.09

go-restful

0%-0.5%

34M

51757.61

go-iris

0%-1%

37M

46041.23

go语言web框架中gin、chi、echo性能相当,gin略显优势,iris实测效果不佳;

go语言与c++语言网络框架比较还是存在一定性能差距,但不是决定性的;

go语言整体资源耗用大,c++足够轻量高效;

go语言真的很易用且简洁!!就是三方依赖太多 ,拿来主义,问题排查那是相当酸爽...... 当然,随着依赖包升级你会一直爽 :)

有疑问加站长微信联系(非本文作者)