From a115f89d356e7c10b4461aeee026fd13d408e6ac Mon Sep 17 00:00:00 2001 From: Oliver Gould Date: Fri, 8 Jun 2018 17:06:56 -0700 Subject: [PATCH] server: Accept a latency distribution on the commandline (#45) * make `distribution` and `percentiles` top-level modules * Support a per-instance latency distribution configured on the server. * update README --- README.md | 43 +++++++++---------- client/client.go | 4 +- cmd/server.go | 1 + .../distribution.go | 0 .../distribution_test.go | 2 +- .../percentiles.go | 0 .../percentiles_test.go | 5 ++- server/server.go | 43 +++++++++++++------ 8 files changed, 57 insertions(+), 41 deletions(-) rename {client/distribution => distribution}/distribution.go (100%) rename {client/distribution => distribution}/distribution_test.go (99%) rename {client/percentiles => percentiles}/percentiles.go (100%) rename {client/percentiles => percentiles}/percentiles_test.go (96%) diff --git a/README.md b/README.md index 904fb7f9..6fe2ce88 100644 --- a/README.md +++ b/README.md @@ -8,16 +8,16 @@ Strest client and server implementations for gRPC. To run the client and server locally, first start the server. -```bash -$ go run main.go server +``` +$ strest-grpc server starting gRPC server on :11111 ``` Next run the client. By default, the client will send as many request as it can on a single connection for 10 seconds, and exit with a performance report. -```bash -$ go run main.go client --address localhost:11111 +``` +$ strest-grpc client --address localhost:11111 2017-05-12T16:17:40-07:00 98.2KB 354/0 10s L: 0 [ 89 97 ] 102 J: 0 0 { "good": 354, @@ -40,12 +40,10 @@ $ go run main.go client --address localhost:11111 ### Usage -Use the `--help` flag for usage information. - #### Commands -```bash -$ go run main.go --help +``` +$ strest-grpc --help A load tester for stress testing grpc intermediaries. Find more information at https://github.com/buoyantio/strest-grpc. @@ -68,8 +66,8 @@ Use "strest-grpc [command] --help" for more information about a command. #### Client -```bash -$ go run main.go client --help +``` +$ strest-grpc client --help run the strest-grpc client Usage: @@ -102,20 +100,21 @@ Global Flags: #### Server -```bash -$ go run main.go server --help +``` +$ strest-grpc server --help run the strest-grpc server Usage: strest-grpc server [flags] Flags: - --address string address to serve on (default ":11111") - -h, --help help for server - --metricAddr string address to serve metrics on - --tlsCertFile string the path to the trust certificate - --tlsPrivKeyFile string the path to the server's private key - -u, --unix use Unix Domain Sockets instead of TCP + --address string address to serve on (default ":11111") + -h, --help help for server + --latencyPercentiles string response latency percentile distribution added to client latencies. (e.g. 50=10,100=100) (default "100=0") + --metricAddr string address to serve metrics on + --tlsCertFile string the path to the trust certificate + --tlsPrivKeyFile string the path to the server's private key + -u, --unix use Unix Domain Sockets instead of TCP Global Flags: -l, --logLevel string log level, must be one of: panic, fatal, error, warn, info, debug (default "info") @@ -123,8 +122,8 @@ Global Flags: #### Max-RPS -```bash -$ go run main.go max-rps --help +``` +$ strest-grpc max-rps --help compute max RPS Usage: @@ -144,7 +143,7 @@ Global Flags: To build the strest-grpc binaries and archives, run: -```bash +``` ./bin/release.sh [VERSION TAG] ``` @@ -152,7 +151,7 @@ That will create `strest-grpc` binaries and archives in `./release`. To build a docker image, run: -```bash +``` $ docker build -t buoyantio/strest-grpc:latest . ``` diff --git a/client/client.go b/client/client.go index 1806ca89..6df82262 100644 --- a/client/client.go +++ b/client/client.go @@ -17,8 +17,8 @@ import ( "syscall" "time" - "github.com/buoyantio/strest-grpc/client/distribution" - "github.com/buoyantio/strest-grpc/client/percentiles" + "github.com/buoyantio/strest-grpc/distribution" + "github.com/buoyantio/strest-grpc/percentiles" pb "github.com/buoyantio/strest-grpc/protos" "github.com/codahale/hdrhistogram" "github.com/prometheus/client_golang/prometheus" diff --git a/cmd/server.go b/cmd/server.go index 12cbc4d3..96fad5cf 100644 --- a/cmd/server.go +++ b/cmd/server.go @@ -21,6 +21,7 @@ func init() { flags := serverCmd.Flags() flags.StringVar(&serverCfg.Address, "address", ":11111", "address to serve on") flags.StringVar(&serverCfg.MetricAddr, "metricAddr", "", "address to serve metrics on") + flags.StringVar(&serverCfg.LatencyPercentiles, "latencyPercentiles", "100=0", "response latency percentile distribution added to client latencies. (e.g. 50=10,100=100)") flags.BoolVarP(&serverCfg.UseUnixAddr, "unix", "u", false, "use Unix Domain Sockets instead of TCP") flags.StringVar(&serverCfg.TLSCertFile, "tlsCertFile", "", "the path to the trust certificate") flags.StringVar(&serverCfg.TLSPrivKeyFile, "tlsPrivKeyFile", "", "the path to the server's private key") diff --git a/client/distribution/distribution.go b/distribution/distribution.go similarity index 100% rename from client/distribution/distribution.go rename to distribution/distribution.go diff --git a/client/distribution/distribution_test.go b/distribution/distribution_test.go similarity index 99% rename from client/distribution/distribution_test.go rename to distribution/distribution_test.go index 0e1cd8a4..91483e57 100644 --- a/client/distribution/distribution_test.go +++ b/distribution/distribution_test.go @@ -3,7 +3,7 @@ package distribution_test import ( "testing" - "github.com/buoyantio/strest-grpc/client/distribution" + "github.com/buoyantio/strest-grpc/distribution" . "gopkg.in/check.v1" ) diff --git a/client/percentiles/percentiles.go b/percentiles/percentiles.go similarity index 100% rename from client/percentiles/percentiles.go rename to percentiles/percentiles.go diff --git a/client/percentiles/percentiles_test.go b/percentiles/percentiles_test.go similarity index 96% rename from client/percentiles/percentiles_test.go rename to percentiles/percentiles_test.go index c2aefc28..8b9d0dc1 100644 --- a/client/percentiles/percentiles_test.go +++ b/percentiles/percentiles_test.go @@ -1,9 +1,10 @@ package percentiles_test import ( - "github.com/buoyantio/strest-grpc/client/percentiles" - . "gopkg.in/check.v1" "testing" + + "github.com/buoyantio/strest-grpc/percentiles" + . "gopkg.in/check.v1" ) // Hook up gocheck into the "go test" runner. diff --git a/server/server.go b/server/server.go index 22a403e7..717ac10e 100644 --- a/server/server.go +++ b/server/server.go @@ -9,7 +9,8 @@ import ( "net/http" "time" - "github.com/buoyantio/strest-grpc/client/distribution" + "github.com/buoyantio/strest-grpc/distribution" + "github.com/buoyantio/strest-grpc/percentiles" pb "github.com/buoyantio/strest-grpc/protos" "github.com/buoyantio/strest-grpc/server/random_string" "github.com/prometheus/client_golang/prometheus" @@ -22,7 +23,9 @@ import ( "google.golang.org/grpc/status" ) -type server struct{} +type server struct { + latencyDistribution distribution.Distribution +} var ( promRequests = prometheus.NewCounter(prometheus.CounterOpts{ @@ -57,8 +60,10 @@ func registerMetrics() { func (s *server) Get(ctx context.Context, in *pb.ResponseSpec) (*pb.ResponseReply, error) { var src = rand.NewSource(time.Now().UnixNano()) r := rand.New(src) - if in.Latency > 0 { - time.Sleep(time.Duration(in.Latency) * time.Millisecond) + latency := s.latencyDistribution.Get(r.Int31() % 1000) + latency = latency + in.Latency + if latency > 0 { + time.Sleep(time.Duration(latency) * time.Millisecond) } promRequests.Inc() promResponses.Inc() @@ -146,13 +151,14 @@ func (s *server) StreamingGet(stream pb.Responder_StreamingGetServer) error { } } -// Configuration for a server +// Config holds the commandline configuration for the server. type Config struct { - Address string - UseUnixAddr bool - MetricAddr string - TLSCertFile string - TLSPrivKeyFile string + Address string + UseUnixAddr bool + MetricAddr string + LatencyPercentiles string + TLSCertFile string + TLSPrivKeyFile string } func (cfg *Config) serveMetrics() { @@ -168,9 +174,9 @@ func (cfg *Config) serveMetrics() { func (cfg *Config) af() string { if cfg.UseUnixAddr { return "unix" - } else { - return "tcp" } + + return "tcp" } func (cfg *Config) tlsCreds() (credentials.TransportCredentials, error) { @@ -180,10 +186,19 @@ func (cfg *Config) tlsCreds() (credentials.TransportCredentials, error) { return nil, nil } -// run the server +// Run processes commandline configuration and runs the server. func (cfg Config) Run() { rand.Seed(time.Now().UnixNano()) + latencyPercentiles, err := percentiles.ParsePercentiles(cfg.LatencyPercentiles) + if err != nil { + log.Fatalf("latencyPercentiles was not valid: %v", err) + } + latencyDistribution, err := distribution.FromMap(latencyPercentiles) + if err != nil { + log.Fatalf("unable to create latency distribution: %v", err) + } + cfg.serveMetrics() fmt.Println("starting gRPC server on", cfg.Address) @@ -205,6 +220,6 @@ func (cfg Config) Run() { s := grpc.NewServer(opts...) - pb.RegisterResponderServer(s, new(server)) + pb.RegisterResponderServer(s, &server{latencyDistribution}) s.Serve(lis) }