Home

Awesome

Trunks Build Status

Trunks, like every son, is derived from the father Vegeta with some enhanced skills:

  1. dump HTTP reponses
  2. gRPC support

Trunks

Current Tag v13.0.0

Usage manual

for original usage of Vegeta, please refer to vegeta' readme

More functionalities

dump http attck response to file

(add one more option '-respf' to 'attack')
-respf string
      Dump responses to file

gRPC perf test (as lib)

Trunks uses the burn to attack the gRPC services. Capable with any gRPC service.

Given multiple hosts ('IP:port' of service instances), Trunks will use simple round-robin as client-side load balance mechanism.

Burning duration is shorter. No need to do the real service discovery or watch / real-time live connection's update. Say, if testing service instances registered to Etcd, we don't need to watch the status of all instances and adjust the connection pool. During the short time of perf testing, we assume the instance hosts are not-changing.

Example:

This example is using "google.golang.org/grpc/examples/route_guide" as the target server.

package main

import (
    "fmt"
    "time"

    trunks "github.com/straightdave/trunks/lib"
    // for convenience, change the client_stub.pb.go into package main
)

func main() {
    tgt := &trunks.Gtarget{
        MethodName: "/routeguide.RouteGuide/GetFeature",
        Requests:   []proto.Message{&Point{Latitude: 10000, Longitude: 10000}}, // supporting multiple requests
        Response:   &Feature{}, // providing one response data struct
    }

    burner, err := trunks.NewBurner(
        []string{"192.168.0.1:8087"},  // server address pool; simple round-robin
        trunks.WithLooping(true),      // loop requests; false by default
        trunks.WithNumWorker(20),      // worker goroutine pool size; 10 is default
        trunks.WithDumpFile("a.dump"), // dump responses to file
    )
    if err != nil {
        fmt.Println(err)
        return
    }
    defer burner.Close()

    var metrics trunks.Metrics
    startT := time.Now()

    // burning the target service with QPS=5 and Duration=10s
    for res := range burner.Burn(tgt, uint64(5), 10*time.Second) {
        metrics.Add(res)
    }
    dur := time.Since(startT)
    metrics.Close()

    fmt.Printf("dur: %v\n", dur.Seconds())
    fmt.Printf("earliest: %v\n", metrics.Earliest.Sub(startT).Nanoseconds())
    fmt.Printf("latest: %v\n", metrics.Latest.Sub(startT).Nanoseconds())
    fmt.Printf("end: %v\n", metrics.End.Sub(startT).Nanoseconds())
    fmt.Printf("reqs: %d\n", metrics.Requests)
    fmt.Printf("success%: %f\n", metrics.Success)
    fmt.Printf("p50: %s\n", metrics.Latencies.P50)
    fmt.Printf("p95: %s\n", metrics.Latencies.P95)
    fmt.Printf("p99: %s\n", metrics.Latencies.P99)
    fmt.Printf("mean: %s\n", metrics.Latencies.Mean)
    fmt.Printf("max: %s\n", metrics.Latencies.Max)
    // ...
}

For this code snippet, it would result in:

dur: 9.802099215
earliest: 68670
latest: 9800068577
end: 9802058490
reqs: 50
success%: 99.88
p50: 5.974748ms
p95: 6.084433ms
p99: 6.10946ms
mean: 5.143272ms
max: 6.19225ms

Arion as gRPC

Arion makes it easy to use Trunks. Please check https://github.com/straightdave/arion