Skip to content

Instantly share code, notes, and snippets.

@madawei2699
Last active April 23, 2022 05:25
Show Gist options
  • Save madawei2699/c73f520f28b77572b233e23b462186ce to your computer and use it in GitHub Desktop.
Save madawei2699/c73f520f28b77572b233e23b462186ce to your computer and use it in GitHub Desktop.
Go API Server with remote request benchmark test

Upstream test server source code: https://gist.github.com/madawei2699/760a896c442408bf6a4475bd98eff2c8

Goroutine Version

package main

import (
	"encoding/json"
	"net/http"
	"sync"
	"time"

	"github.com/labstack/echo/v4"
	"github.com/labstack/echo/v4/middleware"
)

func main() {
	// Echo instance
	e := echo.New()

	// Middleware
	e.Use(middleware.Logger())
	e.Use(middleware.Recover())

	// Routes
	e.GET("/", hello)
	e.GET("/proxy", sendJson)

	// Start server
	e.Logger.Fatal(e.Start(":3333"))
}

// Handler
func hello(c echo.Context) error {
	return c.String(http.StatusOK, "Hello, World!")
}

type TestJson struct {
	BytesOut   string `json:"bytes_out"`
	Developer  string `json:"developer"`
	IP         string `json:"ip"`
	Name       string `json:"name"`
	Method     string `json:"method"`
	Protocol   string `json:"protocol"`
	StatusCode string `json:"status_code"`
	Time       string `json:"time"`
}

var myClient = &http.Client{Timeout: 10 * time.Second}

func getJson(url string, target interface{}) error {
	r, err := myClient.Get(url)
	if err != nil {
		return err
	}
	defer r.Body.Close()

	return json.NewDecoder(r.Body).Decode(target)
}

func sendJson(c echo.Context) error {
	goroutine := 5
	dataSlice := make([]*TestJson, goroutine)

	var wg sync.WaitGroup
	wg.Add(goroutine)

	for g := 0; g < goroutine; g++ {
		go func(g int) {
			defer wg.Done()
			r := new(TestJson)
			getJson("http://localhost:1323/json", r)
			dataSlice[g] = r
		}(g)
	}
	wg.Wait()
	return c.JSON(200, map[string]interface{}{
		"data": []interface{}{dataSlice},
	})
}

wrk -t12 -c12 -d30s http://localhost:3333/proxy

Running 30s test @ http://localhost:3333/proxy
  12 threads and 12 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    49.23ms   35.61ms 222.78ms   62.95%
    Req/Sec    21.97     16.59    80.00     77.30%
  7778 requests in 30.11s, 7.26MB read
Requests/sec:    258.35
Transfer/sec:    247.08KB

wrk -t12 -c20 -d30s http://localhost:3333/proxy

Running 30s test @ http://localhost:3333/proxy
  12 threads and 20 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    49.98ms  109.09ms   1.12s    96.10%
    Req/Sec    31.95     32.41   161.00     78.31%
  10735 requests in 30.10s, 9.99MB read
Requests/sec:    356.59
Transfer/sec:    339.80KB

wrk -t12 -c200 -d30s http://localhost:3333/proxy

Running 30s test @ http://localhost:3333/proxy
  12 threads and 200 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   191.38ms  199.94ms   1.93s    93.47%
    Req/Sec    89.23     38.76   240.00     65.14%
  29573 requests in 30.10s, 27.28MB read
  Socket errors: connect 0, read 40, write 0, timeout 93
Requests/sec:    982.56
Transfer/sec:      0.91MB

Without Goroutine Version

wrk -t12 -c20 -d30s http://localhost:3333/proxy

Running 30s test @ http://localhost:3333/proxy
  12 threads and 20 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    20.18ms   26.47ms 387.13ms   88.58%
    Req/Sec    60.49     42.33   202.00     69.79%
  21414 requests in 30.11s, 19.76MB read
Requests/sec:    711.30
Transfer/sec:    672.20KB

wrk -t12 -c12 -d30s http://localhost:3333/proxy

Running 30s test @ http://localhost:3333/proxy
  12 threads and 12 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    17.37ms   22.32ms 340.98ms   90.06%
    Req/Sec    78.97     37.90   190.00     59.28%
  28099 requests in 30.08s, 25.87MB read
Requests/sec:    934.03
Transfer/sec:      0.86MB

wrk -t12 -c200 -d30s http://localhost:3333/proxy

Running 30s test @ http://localhost:3333/proxy
  12 threads and 200 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   472.61ms  367.91ms   1.68s    72.00%
    Req/Sec    42.80     41.71   171.00     79.72%
  12816 requests in 30.09s, 11.85MB read
  Socket errors: connect 0, read 70, write 0, timeout 0
Requests/sec:    425.91
Transfer/sec:    403.41KB
module example.com/try-proxy
go 1.17
require github.com/labstack/echo/v4 v4.7.2
require (
github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
github.com/labstack/gommon v0.3.1 // indirect
github.com/mattn/go-colorable v0.1.11 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasttemplate v1.2.1 // indirect
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 // indirect
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f // indirect
golang.org/x/sys v0.0.0-20211103235746-7861aae1554b // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/time v0.0.0-20201208040808-7e3f01d25324 // indirect
)
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
github.com/labstack/echo/v4 v4.7.2 h1:Kv2/p8OaQ+M6Ex4eGimg9b9e6icoxA42JSlOR3msKtI=
github.com/labstack/echo/v4 v4.7.2/go.mod h1:xkCDAdFCIf8jsFQ5NnbK7oqaF/yU1A1X20Ltm0OvSks=
github.com/labstack/gommon v0.3.1 h1:OomWaJXm7xR6L1HmEtGyQf26TEn7V6X88mktX9kee9o=
github.com/labstack/gommon v0.3.1/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM=
github.com/mattn/go-colorable v0.1.11 h1:nQ+aFkoE2TMGc0b68U2OKSexC+eq46+XwZzWXHRmPYs=
github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasttemplate v1.2.1 h1:TVEnxayobAdVkhQfrfes2IzOB6o+z4roRkPF52WA1u4=
github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 h1:HWj/xjIHfjYU5nVXpTM0s39J9CbLn7Cc5a7IC5rwsMQ=
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f h1:OfiFi4JbukWwe3lzw+xunroH1mnC1e2Gy5cxNJApiSY=
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211103235746-7861aae1554b h1:1VkfZQv42XQlA/jchYumAnv1UPo6RgF9rJFkTgZIxO4=
golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/time v0.0.0-20201208040808-7e3f01d25324 h1:Hir2P/De0WpUhtrKGGjvSb2YxUgyZ7EFOSLIcSSpiwE=
golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
package main
import (
"encoding/json"
"net/http"
"time"
"github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware"
)
func main() {
// Echo instance
e := echo.New()
// Middleware
e.Use(middleware.Logger())
e.Use(middleware.Recover())
// Routes
e.GET("/", hello)
e.GET("/proxy", sendJson)
// Start server
e.Logger.Fatal(e.Start(":3333"))
}
// Handler
func hello(c echo.Context) error {
return c.String(http.StatusOK, "Hello, World!")
}
type TestJson struct {
BytesOut string `json:"bytes_out"`
Developer string `json:"developer"`
IP string `json:"ip"`
Name string `json:"name"`
Method string `json:"method"`
Protocol string `json:"protocol"`
StatusCode string `json:"status_code"`
Time string `json:"time"`
}
var myClient = &http.Client{Timeout: 10 * time.Second}
func getJson(url string, target interface{}) error {
r, err := myClient.Get(url)
if err != nil {
return err
}
defer r.Body.Close()
return json.NewDecoder(r.Body).Decode(target)
}
func sendJson(c echo.Context) error {
r1 := new(TestJson)
r2 := new(TestJson)
r3 := new(TestJson)
r4 := new(TestJson)
r5 := new(TestJson)
getJson("http://localhost:1323/json", r1)
getJson("http://localhost:1323/json", r2)
getJson("http://localhost:1323/json", r3)
getJson("http://localhost:1323/json", r4)
getJson("http://localhost:1323/json", r5)
return c.JSON(200, map[string]interface{}{
"data": []interface{}{r1, r2, r3, r4, r5},
})
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment