gRPC enables efficient communication between services through a high-performance and lightweight protocol, making it an excellent choice for real-time, resource-intensive applications. Companies like Square, Cockroach Labs, and Juniper Networks rely on gRPC to handle massive data loads and millions of concurrent requests.
Gatling supports gRPC, allowing developers to load test gRPC-based services. This article illustrates how to load test gRPC applications using Gatling. We’ll create a simulation to load test a gRPC application and evaluate its performance under load.
If you want to understand what gRPC is and why it's important, you can check this article.
The Gatling gRPC plugin supports testing applications and microservices that use gRPC. The plugin is available under the Gatling Enterprise component license.
There are built-in limitations on the open-source version, such as a 5-minute test duration, which enforces the crafting and debugging intention. The unlimited version of the plugin is only available when executing load tests on Gatling Enterprise.
First, ensure you have Gatling installed and set up. If you haven't already, download it from the official documentation.
Now clone the project from GitHub and open the GreetingSimulation on your IDE.
A proto (protocol buffer) in gRPC is a language-agnostic data serialization format that defines the structure of messages and services using an interface definition language. It allows you to specify how you want your data to be structured and typed, and gRPC uses this definition to automatically generate code in multiple languages. In our case, we will use the Greeting proto.
Our proto is composed of 2 services: Greet and GreetWithDeadline. The two functions take a first and last name and greet you. We will also test the deadline of gRPC using the second function and Gatling.
First, we need to import the libraries we need to launch our simulation. For the greetings simulation, we need these libraries:
package io.gatling.grpc.demo;
import java.time.Duration;
import java.util.function.Function;
import io.gatling.grpc.demo.greeting.*;
import io.gatling.javaapi.core.*;
import io.gatling.javaapi.grpc.*;
import io.grpc.Status;
import static io.gatling.javaapi.core.CoreDsl.*;
import static io.gatling.javaapi.grpc.GrpcDsl.*;
After that, we need to set up our base protocol for Gatling to connect to our gRPC application.
public class GreetingSimulation extends Simulation {
GrpcProtocolBuilder baseGrpcProtocol = grpc.forAddress("localhost", 50051)
.channelCredentials("#{channelCredentials}")
.overrideAuthority("gatling-grpc-demo-test-server");
The gRPC Protocol Builder tells Gatling to connect to our gRPC application using channel credentials and by overriding the Authority. Now that we are connected, we need to define the user journey of our users.
Now, we need to create a function that will take the first and last names from the session and pass them to the builder of our service.
Function<Session, Greeting> greeting = session -> {
String firstName = session.getString("firstName");
String lastName = session.getString("lastName");
return Greeting.newBuilder()
.setFirstName(firstName)
.setLastName(lastName)
.build();
};
This function retrieves the first and last name from the session and creates the Greeting service using our first and last names as arguments. We will use it inside our two scenarios.
So in our first scenario, we want to test if the service Greet works by checking its status code and the responses we get. To do this, here is the Gatling code:
ScenarioBuilder unary = scenario("Greet Unary")
.feed(Feeders.channelCredentials().circular())
.feed(Feeders.randomNames())
.exec(grpc("Greet")
.unary(GreetingServiceGrpc.getGreetMethod())
.send(session -> GreetRequest.newBuilder()
.setGreeting(greeting.apply(session))
.build())
.check(
statusCode().is(Status.Code.OK),
response(GreetResponse::getResult).isEL("Hello #{firstName} #{lastName}")));
Let me explain it to you:
So in our second scenario, we want to test the same thing but we add a deadline.
ScenarioBuilder deadlines = scenario("Greet w/ Deadlines")
.feed(Feeders.channelCredentials().circular())
.feed(Feeders.randomNames())
.exec(grpc("Greet w/ Deadlines")
.unary(GreetingServiceGrpc.getGreetWithDeadlineMethod())
.send(session -> GreetRequest.newBuilder()
.setGreeting(greeting.apply(session))
.build())
.deadlineAfter(Duration.ofMillis(100))
.check(statusCode().is(Status.Code.DEADLINE_EXCEEDED)));
You can see that it's almost the same scenario, as the only thing changing is:
.deadlineAfter(Duration.ofMillis(100))
.check(statusCode().is(Status.Code.DEADLINE_EXCEEDED)));
In some applications, you need to set a deadline. If the server takes more time to answer, the request will be terminated and you will get an error. In our case, we will wait 100ms and then check if the server returns the error code "DEADLINE_EXCEEDED".
The general purpose of this is to prevent requests from hanging indefinitely and ensure system responsiveness by enforcing strict time constraints, allowing applications to fail fast and handle timeouts gracefully rather than leaving users waiting.
Now we need to tell Gatling what pattern the users will follow. In our case, here is the injection profile:
{
String name = System.getProperty("grpc.scenario");
ScenarioBuilder scn;
if ("deadlines".equals(name)) {
scn = deadlines;
} else {
scn = unary;
}
setUp(scn.injectOpen(atOnceUsers(5))).protocols(baseGrpcProtocol);
}
}
First, we get a system property to know which scenario the user wants to run, and then we send 5 users to test this scenario.
To launch the server, open a terminal and run (in the root folder):
./certificates
cd server
./gradlew -PmainClass=io.gatling.grpc.demo.server.greeting.GreetingServer run
To launch the load test, open a terminal and run (in the java/maven folder):
./mvnw gatling:test -Dgrpc.scenario=unary -Dgatling.simulationClass=io.gatling.grpc.demo.GreetingSimulation
or
./mvnw gatling:test -Dgrpc.scenario=deadlines -Dgatling.simulationClass=io.gatling.grpc.demo.GreetingSimulation
After the simulation is complete, Gatling generates an HTML link in the terminal to access your report. Review metrics such as response times, successful and failed connections, and other indicators to identify potential issues with your service.
Let's see how to run a simulation using Gatling Enterprise. First, you need to create an API key on Gatling Enterprise. To do this, you can check our documentation. Now you need to run these commands:
export GATLING_ENTERPRISE_API_TOKEN=<your_token>
./mvnw gatling:enterpriseDeploy
Now on Gatling Entreprise → Package, you will see a new package:
Next, create a simulation by navigating to the "Simulations" tab and clicking "Create New." Select your package from the dropdown list, then click "Create" and configure your simulation settings. (You can set the gRPC.scenario environment variable in the load generator parameters if you want to run the scenario with deadlines)
Now click on the #1 to get the data of our scenario
Now we see a small summary of the report with 5 users. If you want to view the whole report, you can click on the report tab. Also, we offer integrations with many different tools if you want to streamline your load testing process.
We've explored how to load test gRPC applications using Gatling. We also walked through setting up a practical example that demonstrates both basic gRPC testing and deadline handling, two critical aspects of modern micro-service architectures.
If you want to go deeper, you can check our documentation also also try Gatling Entreprise. You will get access to CI/CD integration, detailed reporting, private locations, and many more features to ensure your gRPC services perform reliably under load.
The example we've explored, though simple, showcases essential testing patterns that can be adapted for more complex scenarios. Whether you're using the open-source version for initial testing or the enterprise version for comprehensive load testing, Gatling provides the necessary tools to verify the performance and reliability of your gRPC services in real-world conditions.