Home Technology Benchmarking gRPC powered micro-services

Benchmarking gRPC powered micro-services

by rakesh kumar

At BigBasket, we are in the process of breaking the monolith application into a number of Microservices. One of the most challenging parts of this process is to efficiently connect the polyglot services. We are using gRPC for high-performance communication between the services. This works beautifully but the big challenge is in benchmarking the performance of the microservices over gRPC. The objective of this post is to benchmark the communication between gRPC client & server using Apache JMeter.

About gRPC:

gRPC is a high-performance cross-platform RPC framework which helps us efficiently connect different services. Although JSON over REST is the most preferred combination today, gRPC gives a lot more efficiency when compared to textual JSON mixed with REST. The reason for this is because gRPC works on HTTP/2.0 protocol compared to the old and less efficient HTTP/1.1 protocol. gRPC allows a client application to directly call methods on a remote server application which may be running in a completely different environment and platform.

About protocol-buffers:

Protocol-buffers or simply called as protobuf is google’s platform-neutral, open source mechanism for serializing structured data for use in communications protocols. The basic step involved in working with gRPC is to define the rules of communication between client and server inside a proto file. Proto file is a ordinary text file with a .proto extension. A basic proto file looks something like this:

syntax = "proto3";

option java_multiple_files = true;
option java_package = "io.grpc.java.testing_service";
option java_outer_classname = "TestingServiceProto";
option objc_class_prefix = "HLW";

package testing_service;

service Testing {
	rpc TestingRequestHandler (TestingRequest) returns (TestingResponse) {}

	message TestingRequest {
  	string var_one=1;
  	string var_two = 2;
        string var_three = 3;

	message TestingResponse {
  	string response = 1;

There are three important parts in a typical proto file: Syntax, service and message. Syntax defines the protocol buffer version to be used by both client and server.

‘syntax=proto2’ is the default protocol buffer version but it is recommended to use proto3 with gRPC because of its simplified syntax and better language support. More details about protobuf can be found at https://developers.google.com/protocol-buffers/docs/overview. We are going to use above mentioned protobuf data as a reference in our example.

Benchmarking gRPC communication using JMeter:

JMeter is a pure Java open source software, designed to load test functional behaviour and measuring the performance of a variety of services. Although JMeter comes pre-installed with cool plugins and samplers which are helpful for testing all kind of web-services, no direct plugins for gRPC applications. But the great thing about JMeter is that it allows users to use custom samplers with JMeter to perform load testing.

Below steps are required to load test a gRPC application:

  • Writing a gRPC client in Java
  • Writing a JMeter custom sampler in Java
  • Exporting project jar to JMeter external library folder
  • Using the custom Java Request sampler inside JMeter

PS: Server-side implementation of rpc is out of scope for this post.

Step 1/4: Writing gRPC client in Java

The first step of benchmarking gRPC request is to create a maven project and place the proto file in any source package. Other build tools like gradle can also be used for this. Next step is to include a protobuf compiler plugin in the project which compiles the proto file and generates data access classes in the target folder. Include following protobuf compiler plugin in pom.xml.


Once the above plugin is included in the project, build your project to generate data access classes. In the target folder, six Java classes will be generated for the given proto file. These are:

  • TestingBlockingStub.java
  • TestingGrpc.java
  • TestingRequest.java
  • TestingRequestOrBuilder.java
  • TestingResponse.java
  • TestingResponseOrBuilder.java
  • TestingServiceProto.java

Once these data access classes are generated, we can start writing our Java client inside a new class “TestingServiceClient.java”.

The first step is to create a channel. We are using “NettyChannelBuilder” for creating a ManagedChannel.
Next step is to create a blocking stub, which waits for the server to respond, and will either return a response or raise an exception.
Third step is to create custom request invoking remote methods and sending it to the server via ‘stub’ created in previous step.

The client can communicate with the server now. A public method needs to be exposed, which can be used by our JMeter sampler to send final request.

To inject desired metadata headers into request we create a custom client interceptor “HeaderClientInterceptor.java”

package example.grpc.clients.testing_service;

import io.grpc.CallOptions;
import io.grpc.Channel;
import io.grpc.ClientCall;
import io.grpc.ClientInterceptor;
import io.grpc.ForwardingClientCall.SimpleForwardingClientCall;
import io.grpc.ForwardingClientCallListener.SimpleForwardingClientCallListener;
import io.grpc.Metadata;
import io.grpc.MethodDescriptor;

public class HeaderClientInterceptor implements ClientInterceptor {
	public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(MethodDescriptor<ReqT, RespT> method,
			CallOptions callOptions, Channel next) {
		return new SimpleForwardingClientCall<ReqT, RespT>(next.newCall(method, callOptions)) {
			public void start(Listener<RespT> responseListener, Metadata headers) {
				if (headers != null) {
					Metadata fixedHeaders = new Metadata();
					Metadata.Key<String> key = Metadata.Key.of("header", Metadata.ASCII_STRING_MARSHALLER);
					fixedHeaders.put(key, "hiiii");
				super.start(new SimpleForwardingClientCallListener<RespT>(responseListener) {
					public void onHeaders(Metadata headers) {
				}, headers);

End result should be:

package example.grpc.clients.testing_service;

import java.util.concurrent.TimeUnit;

import io.grpc.ManagedChannel;
import io.grpc.Metadata;
import io.grpc.java.testing_service.TestingGrpc;
import io.grpc.java.testing_service.TestingGrpc.TestingBlockingStub;
import io.grpc.java.testing_service.TestingRequest;
import io.grpc.java.testing_service.TestingResponse;
import io.grpc.netty.NettyChannelBuilder;

public class TestingServiceClient {

	public ManagedChannel channel;
	public TestingBlockingStub stub;
	public TestingRequest request;
	public Metadata header;

	public static void main(String args[]) {

	public TestingServiceClient(String host, int port) {
		this.channel = createChannel(host, port);
		this.stub = createBlockingStub(this.channel);

	public ManagedChannel createChannel(String host, int port) {
		channel = NettyChannelBuilder.forAddress(host, port).usePlaintext().build();
		return channel;

	public TestingBlockingStub createBlockingStub(ManagedChannel channel) {
		stub = TestingGrpc.newBlockingStub(channel);
		return stub;

	public TestingServiceClient createTestingRequest(String varOne, String varTwo, String varThree) {
		request = TestingRequest.newBuilder().setVarOne(varOne).setVarTwo(varTwo).setVarThree(varThree).build();
		return this;

	public TestingResponse sendRequestToService(TestingServiceClient client, String varOne, String varTwo,
			String varThree) {
		client = client.createTestingRequest(varOne, varTwo, varThree);

		TestingResponse serverResponse = stub.withInterceptors(new HeaderClientInterceptor())
		return serverResponse;

	public void shutdown() throws InterruptedException {
		channel.shutdown().awaitTermination(5, TimeUnit.SECONDS);


Step 2/4: Writing a Jmeter custom sampler in Java

In any source package, create a JMeter sampler “TestingServiceSampler.java” which extends apache JMeter library “AbstractJavaSamplerClient”.

Our Sampler should look like this:

package example.grpc.clients.testing_service.jmeter;

import org.apache.jmeter.config.Arguments;
import org.apache.jmeter.protocol.java.sampler.AbstractJavaSamplerClient;
import org.apache.jmeter.protocol.java.sampler.JavaSamplerContext;
import org.apache.jmeter.samplers.SampleResult;

import example.grpc.clients.testing_service.TestingServiceClient;
import io.grpc.StatusRuntimeException;

public class TestingServiceSampler extends AbstractJavaSamplerClient {

	TestingServiceClient bclient = null;
	String varOne = "one";
	String varTwo = "two";
	String varThree = "three";

	public void setupTest(JavaSamplerContext context) {
		String environment = context.getParameter("host");
		String port = context.getParameter("port");
		this.varOne = context.getParameter("varOne");
		this.varTwo = context.getParameter("varTwo");
		this.varThree = context.getParameter("varThree");
		this.bclient = new TestingServiceClient(environment, Integer.parseInt(port));

	public Arguments getDefaultParameters() {
		Arguments defaultParameters = new Arguments();
		defaultParameters.addArgument("host", "abc.xyz.com");
		defaultParameters.addArgument("port", "5556");
		defaultParameters.addArgument("varOne", varOne);
		defaultParameters.addArgument("varTwo", varTwo);
		defaultParameters.addArgument("varThree", varThree);
		return defaultParameters;

	public SampleResult runTest(JavaSamplerContext context) {
		SampleResult result = new SampleResult();
		boolean success = true;
		String response = "";

		try {
			response = this.bclient.sendRequestToService(bclient, varOne, varTwo, varThree).toString();
			result.setResponseMessage("Successfully performed backup healthcheck");
			result.setResponseCodeOK(); // 200 code
		} catch (StatusRuntimeException e) {
			result.sampleEnd(); // stop stopwatch
			result.setResponseMessage("Exception: " + e);
			success = false;
			// get stack trace as a String to return as document data
			java.io.StringWriter stringWriter = new java.io.StringWriter();
			e.printStackTrace(new java.io.PrintWriter(stringWriter));
		return result;

	public void teardownTest(JavaSamplerContext context) {
		try {
		} catch (InterruptedException e) {

Step 3/4: Exporting project jar to JMeter external library folder.

Next step is to create a runnable jar for this project and export it to external libraries of JMeter. In eclipse, right click inside project explorer, then

  1. Click “Export..”
  2. Choose “Java -> Runable Jar File”
  3. Select launch configuration and export destination(JMeter/lib/ext)
  4. Finish.

A runnable jar “filename.jar” is exported to JMeter external library folder .

Step 4/4: Using the custom Java Request sampler inside JMeter

We have now successfully created a gRPC request sampler and included it as a part of JMeter. Next step is to start JMeter application inside JMeter/bin/jmeter. Once the JMeter window opens, we can start creating test plan.

Add “User defined variable” from the list of config elements and add following key/value pairs to the User defined variables:

  • threads : ${__P(threads, 100)}
  • rampPeriod : ${__P(rampPeriod, 1)}
  • loopCount : ${__P(loopCount, 5)}
  • host : ${__P(host, abc.xyz.com)}
  • port : ${__P(port, 5556)}

Next, add a loop controller after adding a thread group with thread properties as “$threads” and “$rampPeriod”. Use user variable $loopCount inside loop controller to control number of loops.
Inside loop controller, add a new Sampler of type “Java Request”. Inside Java Request classname, choose our custom java sampler which we exported as a jar. Provide the following properties which were required by our sampler as a parameter:

  • host : ${host}
  • port : ${port}
  • varOne : “one”
  • varTwo : “two”
  • varThree : “three”

Save the test plan in any local directory and close the JMeter window.

Run the following command to start load testing for the given host.

jmeter.sh -Jthreads=5 -JrampPeriod=1 -JloopCount=20 -n -t ./fileName.jmx -l ./results.jtl

JMeter will start sending requests to the gRPC host according to the run parameters and generate a results.jtl file for results.

Source code:
The source code of the example demo is available here:

The objective of this post is to give insight into how JMeter can be used to perform load testing on gRPC powered micro-services. With the server-side implementation already running on a host, this post can help people build a test plan in JMeter to perform load testing on gRPC applications.

You may also like

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: