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.
Benefits of using Gatling to load test gRPC applications
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.
- CI/CD Integration: Gatling integrates seamlessly into your CI/CD pipeline, enabling automated performance testing with every code change.
- Comprehensive Reporting: Gatling's detailed reports offer valuable insights into your application's performance under various load conditions.
- Test as Code: Gatling offers various SDKs to create your testing simulations, providing flexibility and personalization.
- Enterprise Features: Gatling offers enterprise-grade capabilities including distributed load generation, team collaboration features, and advanced monitoring integrations.
Setting up our environment
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.
Explaining the simulation
Proto
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.
Setup of libs and protocol
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.
Setup the user journey
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.
Scenario Greetings
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:
- The first feeder: This one permits getting random credentials to secure the channel.
- The second feeder: This one permits getting random first and last names.
- In the exec part:
- The unary call allows testing unary methods; inside of it, we put the name of the service we want to test (if you want to understand more about unary, client/server stream, check the gRPC documentation)
- In the send section, we create the object we will send to our server and we put the names coming from the second feeder.
- In the check section, we verify that the server returns an OK status and the output string equals the one we provided inside the isEL.
- The unary call allows testing unary methods; inside of it, we put the name of the service we want to test (if you want to understand more about unary, client/server stream, check the gRPC documentation)
Scenario Greetings with Deadlines
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.
Injection profile
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.
Launching the simulation
Setup
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
Open-source version
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.
Enterprise version
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:
🚧 Don’t forget to change the URL in the gRPC protocol 🚧
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.
Conclusion
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.
Share this
You May Also Like
These Related Articles