Skip to content

Commit

Permalink
Merge pull request #67 from yarpc/dev
Browse files Browse the repository at this point in the history
Release latest yab changes as 0.5.0
  • Loading branch information
prashantv authored Jul 18, 2016
2 parents e47a130 + ae84f5c commit 8d57ff4
Show file tree
Hide file tree
Showing 17 changed files with 968 additions and 238 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ install_ci: install
update_man:
go install .
yab --man-page > man/yab.1
nroff -man man/yab.1 | man2html -title yab > man/yab.html
groff -man -T html man/yab.1 > man/yab.html
[[ -d ../yab_ghpages ]] && cp man/yab.html ../yab_ghpages/man.html
@echo "Please update gh-pages"

Expand Down
21 changes: 19 additions & 2 deletions bench_method.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
package main

import (
"math/rand"
"sync"
"time"

Expand Down Expand Up @@ -63,19 +64,35 @@ func (m benchmarkMethod) call(t transport.Transport) (time.Duration, error) {
return duration, err
}

func hostPortBalancer(hostPorts []string) func(i int) string {
numHostPorts := len(hostPorts)
startOffset := rand.Intn(numHostPorts)
return func(i int) string {
offset := (startOffset + i) % numHostPorts
return hostPorts[offset]
}
}

// WarmTransports returns n transports that have been warmed up.
// No requests may fail during the warmup period.
func (m benchmarkMethod) WarmTransports(n int, tOpts TransportOptions, warmupRequests int) ([]transport.Transport, error) {
tOpts, err := loadTransportHostPorts(tOpts)
if err != nil {
return nil, err
}

hostPortFor := hostPortBalancer(tOpts.HostPorts)
transports := make([]transport.Transport, n)
errs := make([]error, n)

var wg sync.WaitGroup
for i := range transports {
wg.Add(1)
go func(i int) {
go func(i int, tOpts TransportOptions) {
defer wg.Done()
tOpts.HostPorts = []string{hostPortFor(i)}
transports[i], errs[i] = m.WarmTransport(tOpts, warmupRequests)
}(i)
}(i, tOpts)
}

wg.Wait()
Expand Down
69 changes: 62 additions & 7 deletions bench_method_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ package main

import (
"fmt"
"math/rand"
"sync/atomic"
"testing"
"time"
Expand All @@ -43,7 +44,7 @@ func benchmarkMethodForTest(t *testing.T, methodString string, p transport.Proto
serializer, err := NewSerializer(rOpts)
require.NoError(t, err, "Failed to create Thrift serializer")

serializer = withTransportSerializer(p, serializer)
serializer = withTransportSerializer(p, serializer, rOpts)

req, err := serializer.Request(nil)
require.NoError(t, err, "Failed to serialize Thrift body")
Expand Down Expand Up @@ -168,22 +169,76 @@ func TestBenchmarkMethodCall(t *testing.T) {
}
}

func TestHostPortBalancer(t *testing.T) {
tests := []struct {
seed int64
hostPorts []string
want []string
}{
{
seed: 1,
hostPorts: []string{"1"},
want: []string{"1", "1", "1"},
},
{
seed: 1,
hostPorts: []string{"1", "2"},
want: []string{"2", "1", "2"},
},
{
seed: 2,
hostPorts: []string{"1", "2"},
want: []string{"1", "2", "1"},
},
{
seed: 1,
hostPorts: []string{"1", "2", "3", "4", "5"},
want: []string{"2", "3", "4"},
},
}

for _, tt := range tests {
rand.Seed(tt.seed)
hostPortFor := hostPortBalancer(tt.hostPorts)
for i, want := range tt.want {
got := hostPortFor(i)
assert.Equal(t, want, got, "hostPortBalancer(%v) seed %v i %v failed", tt.hostPorts, tt.seed, i)
}
}
}

func TestBenchmarkMethodWarmTransportsSuccess(t *testing.T) {
const numServers = 5
m := benchmarkMethodForTest(t, fooMethod, transport.TChannel)
s := newServer(t)
defer s.shutdown()
s.register(fooMethod, methods.echo())

counters := make([]*int32, numServers)
servers := make([]*server, numServers)
serverHPs := make([]string, numServers)
for i := range servers {
servers[i] = newServer(t)
defer servers[i].shutdown()
serverHPs[i] = servers[i].hostPort()

counter, handler := methods.counter()
counters[i] = counter
servers[i].register(fooMethod, handler)
}

tOpts := TransportOptions{
ServiceName: "foo",
HostPorts: []string{s.hostPort()},
HostPorts: serverHPs,
}
transports, err := m.WarmTransports(10, tOpts, 1 /* warmupRequests */)
transports, err := m.WarmTransports(numServers, tOpts, 1 /* warmupRequests */)
assert.NoError(t, err, "WarmTransports should not fail")
assert.Equal(t, 10, len(transports), "Got unexpected number of transports")
assert.Equal(t, numServers, len(transports), "Got unexpected number of transports")
for i, transport := range transports {
assert.NotNil(t, transport, "transports[%v] should not be nil", i)
}

// Verify that each server has received one call.
for i, counter := range counters {
assert.EqualValues(t, 1, *counter, "Server %v received unexpected number of calls", i)
}
}

func TestBenchmarkMethodWarmTransportsError(t *testing.T) {
Expand Down
1 change: 0 additions & 1 deletion benchmark.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,6 @@ func runBenchmark(out output, allOpts Options, m benchmarkMethod) {
out.Printf(" Max RPS: %v\n", opts.RPS)

// Warm up number of connections.
// TODO: If we're making N connections, we should try to select N unique peers
connections, err := m.WarmTransports(numConns, allOpts.TOpts, opts.WarmupRequests)
if err != nil {
out.Fatalf("Failed to warmup connections for benchmark: %v", err)
Expand Down
67 changes: 44 additions & 23 deletions doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@
// THE SOFTWARE.

// yab is a benchmarking tool for TChannel and HTTP applications.
// It's primarily intended for Thrift applications but supports other encodings like JSON and binary (raw).
// It's primarily intended for Thrift applications but supports other encodings
// like JSON and binary (raw).
//
// It can be used in a curl-like fashion when benchmarking features are disabled.
//
Expand All @@ -32,70 +33,88 @@ const _reqOptsDesc = `Configures the request data and the encoding.
To make Thrift requests, specify a Thrift file and pass the Thrift
service and procedure to the method argument (-m or --method) as
Service::Method.
$ yab -p localhost:9787 kv -t kv.thrift -m KeyValue::Count -r '{}'
$ yab -p localhost:9787 kv -t kv.thrift -m KeyValue::Count -r '{}'
You can also use positional arguments to specify the method and body:
$ yab -p localhost:9787 -t kv.thrift kv KeyValue::Count '{}'
$ yab -p localhost:9787 -t kv.thrift kv KeyValue::Count '{}'
The TChannel health endpoint can be hit without specifying a Thrift file
by passing --health.
Thrift requests can be specified as JSON or YAML. For example, for a method
defined as:
void addUser(1: string name, 2: i32 age)
void addUser(1: string name, 2: i32 age)
You can pass the request as JSON: {"name": "Prashant", age: 100}
or as YAML:
name: Prashant
age: 100
name: Prashant
age: 100
The request body can be specified on the command line using -r or --request:
$ yab -p localhost:9787 -t kv.thrift kv KeyValue::Get -r '{"key": "hello"}'
$ yab -p localhost:9787 -t kv.thrift kv \
KeyValue::Get -r '{"key": "hello"}'
Or it can be loaded from a file using -f or --file:
$ yab -p localhost:9787 -t kv.thrift kv KeyValue::Get --file req.yaml
$ yab -p localhost:9787 -t kv.thrift kv KeyValue::Get --file req.yaml
Binary data can be specified in one of many ways:
- As a string or an array of bytes: "data" or [100, 97, 116, 97]
- As base64: {"base64": "ZGF0YQ=="}
- Loaded from a file: {"file": "data.bin"}
* As a string or an array of bytes: "data" or [100, 97, 116, 97]
* As base64: {"base64": "ZGF0YQ=="}
* Loaded from a file: {"file": "data.bin"}
Examples:
$ yab -p localhost:9787 -t kv.thrift kv -m KeyValue::Set -3 '{"key": "hello", "value": [100, 97, 116, 97]}'
$ yab -p localhost:9787 -t kv.thrift kv KeyValue::Set -3 '{"key": "hello", "value": {"file": "data.bin"}}'
$ yab -p localhost:9787 -t kv.thrift kv -m KeyValue::Set \
-r '{"key": "hello", "value": [100, 97, 116, 97]}'
$ yab -p localhost:9787 -t kv.thrift kv KeyValue::Set \
-r '{"key": "hello", "value": {"file": "data.bin"}}'
`

const _transportOptsDesc = `Configures the network transport used to make requests.
yab can target both TChannel and HTTP endpoints. To specify a TChannel endpoint,
specify the peer's host and port:
$ yab -p localhost:9787 [options]
$ yab -p localhost:9787 [options]
or
$ yab -p tchannel://localhost:9787 [options]
$ yab -p tchannel://localhost:9787 [options]
For HTTP endpoints, specify the URL as the peer,
$ yab -p http://localhost:8080/thrift [options]
The Thrift encoded body will be POSTed to the specified URL.
$ yab -p http://localhost:8080/thrift [options]
The Thrift-encoded body will be POSTed to the specified URL.
Multiple peers can be specified using a peer list using -P or --peer-list.
When making a single request, a single peer from this list is selected randomly.
When benchmarking, each connection will randomly select a peer.
$ yab --peer-list hosts.json [options]
When benchmarking, connections will be established in a round-robin fashion,
starting with a random peer.
$ yab --peer-list hosts.json [options]
`

const _benchmarkOptsDesc = `Configures benchmarking, which is disabled by default.
By default, yab will only make a single request. To enable benchmarking, you
must specify the maximum duration for the benchmark by passing -d or --max-duration.
By default, yab will only make a single request. To enable benchmarking,
specify the maximum duration for the benchmark by passing -d or --max-duration.
yab will make requests till either the maximum requests (-n or --max-requests)
yab will make requests until either the maximum requests (-n or --max-requests)
or the maximum duration is reached.
You can control the rate at which yab makes requests using the --rps flag.
An example benchmark command might be:
yab -p localhost:9787 moe --health -n 100000 -d 10s --rps 1000
$ yab -p localhost:9787 moe --health -n 100000 -d 10s --rps 1000
This would make requests at 1000 RPS until either the maximum number of
requests (100,000) or the maximum duration (10 seconds) is reached.
Expand All @@ -105,3 +124,5 @@ CPUs on the machine), but will only have one concurrent call per connection.
The number of connections and concurrent calls per connection can be controlled
using --connections and --concurrency.
`

/* vim: set tabstop=8:softtabstop=8:shiftwidth=8:noexpandtab */
6 changes: 4 additions & 2 deletions glide.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions glide.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,4 @@ import:
version: master
subpackages:
- lib/go/thrift
- package: github.com/casimir/xdg-go
Loading

0 comments on commit 8d57ff4

Please sign in to comment.