測試目的
由于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的
測試環境

環境設定
ulimit -n 2000
壓測工具
wrk
由于環境限制,隻能wrk用戶端和待測試服務端在一台機器上運作
c++自研架構
-
啟動腳本:(最大2000個并發連接配接,2個線程處理,http端口8080)
./proxy_server -i2000 -o2000 -w2 -x8080
- 如有條件測試linux系統可自行下載下傳服務端(選擇對應平台的包):github.com/lazy-luo/smarGate
- 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
- 資源占用:
golang主流高性能web架構性能測試
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(""))
}
$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
-
golang主流高性能web架構性能測試
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"))
}
$ 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
-
golang主流高性能web架構性能測試
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(""))
}
$ 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
-
golang主流高性能web架構性能測試
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))
}
$ 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
-
golang主流高性能web架構性能測試
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)
}
$ 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
-
golang主流高性能web架構性能測試
結論:
- | cpu-free | mem-usage | qps |
---|---|---|---|
c++ | 15%-20% | 6M | 75018.11 |
go-gin | 0%-1.5% | 28M | 61243.74 |
go-chi | 0%-1% | 60658.49 | |
go-echo | 0%-0.5% | 59686.09 | |
go-restful | 34M | 51757.61 | |
go-iris | 37M | 46041.23 |
- go語言web架構中gin、chi、echo性能相當,gin略顯優勢,iris實測效果不佳;
- go語言與c++語言網絡架構比較還是存在一定性能差距,但不是決定性的;
- go語言整體資源耗用大,c++足夠輕量高效;
- go語言真的很易用且簡潔!!就是三方依賴太多 ,拿來主義,問題排查那是相當酸爽...... 當然,随着依賴包更新你會一直爽 :)