Load Test gRPC Services with SLOs¶
Overview
Iter8's load-test-grpc
experiment chart can be used to generate call requests for gRPC services, collect built-in latency and error-related metrics, and validate service-level objectives (SLOs).
Use-cases: Rapid testing, validation, safe rollouts, and continuous delivery (CD) of gRPC services are the motivating use-cases for this experiment type. If the gRPC service satisfies the SLOs, it may be safely rolled out, for example, from a test environment to a production environment.
Your first experiment provides a basic example of using the load-test-http
experiment chart. This tutorial provides additional examples.
Before you try these examples
- Install Iter8.
-
Choose a language, and follow the linked instructions to run the gRPC sample app.
Update step is not needed
The linked instructions show how to update the app, and re-run the updated app. For the purpose of this tutorial, there is no need to update and re-run. Running the basic service is sufficient.
-
Download experiment chart.
iter8 hub -e load-test-grpc cd load-test-grpc
Basic example¶
Load test the gRPC sample service with host
value 127.0.0.1:50051
, fully-qualified method name (call
) helloworld.Greeter.SayHello
, and defined by the Protocol Buffer file located at the protoURL
.
iter8 run --set-string host="127.0.0.1:50051" \
--set-string call="helloworld.Greeter.SayHello" \
--set-string protoURL="https://raw.githubusercontent.com/grpc/grpc-go/master/examples/helloworld/helloworld/helloworld.proto"
View a report of this experiment as described in the quick start tutorial.
Load profile¶
Control the characteristics of the load generated by the load-test-grpc
experiment by setting the number of requests (total
)/duration (duration
), the number of requests per second (rps
), number of connections to use (connections
), and the number of concurrent request workers to use in each connection (concurrency
).
iter8 run --set-string host="127.0.0.1:50051" \
--set-string call="helloworld.Greeter.SayHello" \
--set-string protoURL="https://raw.githubusercontent.com/grpc/grpc-go/master/examples/helloworld/helloworld/helloworld.proto" \
--set data.name="frodo" \
--set total=500 \
--set rps=25 \
--set concurrency=50 \
--set connections=10
The duration value may be any Go duration string.
iter8 run --set-string host="127.0.0.1:50051" \
--set-string call="helloworld.Greeter.SayHello" \
--set-string protoURL="https://raw.githubusercontent.com/grpc/grpc-go/master/examples/helloworld/helloworld/helloworld.proto" \
--set data.name="frodo" \
--set duration="20s" \
--set rps=25 \
--set concurrency=50 \
--set connections=10
When you set total
and qps
, the duration of the load test is automatically determined. Similarly, when you set duration
and qps
, the number of requests is automatically determined. If you set both total
and duration
, the former will be ignored.
Call data¶
gRPC calls may include data serialized as Protocol Buffer messages. Supply them as values, or by pointing to JSON or binary files containing the data.
The protobuf file specifying the gRPC service used in this tutorial defines the following HelloRequest
message format:
message HelloRequest {
string name = 1;
}
Suppose you want include the following HelloRequest
message with every call.
name: frodo
To do so, run the Iter8 experiment as follows.
iter8 run --set-string host="127.0.0.1:50051" \
--set-string call="helloworld.Greeter.SayHello" \
--set-string protoURL="https://raw.githubusercontent.com/grpc/grpc-go/master/examples/helloworld/helloworld/helloworld.proto" \
--set data.name="frodo"
Nested data
Call data may be nested. For example, consider the data:
name: frodo
realm:
planet: earth
location: middle
iter8 run
as follows: --set data.name="frodo" \
--set data.realm.planet="earth" \
--set data.realm.location="middle"
Suppose the call data you want to send is contained in a JSON file and hosted at the url https://location.of/data.json. Iter8 can fetch this JSON file and use the data contained in it during the gRPC load test. To do so, run the experiment as follows.
iter8 run --set-string host="127.0.0.1:50051" \
--set-string call="helloworld.Greeter.SayHello" \
--set-string protoURL="https://raw.githubusercontent.com/grpc/grpc-go/master/examples/helloworld/helloworld/helloworld.proto" \
--set dataURL="https://location.of/data.json"
Suppose that call data you want to send is contained in a binary file as a serialized binary message or multiple count-prefixed messages, and hosted at the url https://location.of/data.bin. Iter8 can fetch this binary file and use the data contained in it during the gRPC load test. To do so, run the experiment as follows.
iter8 run --set-string host="127.0.0.1:50051" \
--set-string call="helloworld.Greeter.SayHello" \
--set-string protoURL="https://raw.githubusercontent.com/grpc/grpc-go/master/examples/helloworld/helloworld/helloworld.proto" \
--set binaryDataURL="https://location.of/data.bin"
data vs dataURL vs binaryDataURL¶
If the call data is shallow and has only a few fields, setting the data
value directly is the easiest of the three approaches. If it is deeply nested, or contains many fields, storing the data as a JSON or binary file, and providing the dataURL
or binaryDataURL
value might be the easier approach. When more than one of these options are specified, the data
field takes precedence over the dataURL
field which in turn takes precedence over the binaryDataURL
field.
Call metadata¶
gRPC calls may include metadata which is information about a particular call. Supply them as values, or by pointing to a JSON file containing the metadata.
You can supply metadata of type map[string]string
(i.e., a map whose keys and values are strings) in the gRPC
load test. Suppose you want to use the following metadata.
darth: vader
lord: sauron
volde: mort
To do so, run the Iter8 experiment as follows.
iter8 run --set-string host="127.0.0.1:50051" \
--set-string call="helloworld.Greeter.SayHello" \
--set-string protoURL="https://raw.githubusercontent.com/grpc/grpc-go/master/examples/helloworld/helloworld/helloworld.proto" \
--set metadata.darth="vader" \
--set metadata.lord="sauron" \
--set metadata.volde="mort"
Suppose the call metadata you want to send is contained in a JSON file and hosted at the url https://location.of/metadata.json. Iter8 can fetch this JSON file and use its contents as the metadata during the gRPC load test. To do so, run the experiment as follows.
iter8 run --set-string host="127.0.0.1:50051" \
--set-string call="helloworld.Greeter.SayHello" \
--set-string protoURL="https://raw.githubusercontent.com/grpc/grpc-go/master/examples/helloworld/helloworld/helloworld.proto" \
--set metadataURL="https://location.of/metadata.json"
metadata vs metadataURL¶
If the call metadata is shallow and has only a few fields, setting the metadata
value directly is the easier approach. If it is deeply nested, or contains many fields, storing the data as a JSON binary file, and providing the metadataURL
value might be the easier approach. When both these options are specified, the metadata
field takes precedence over the metadataURL
field.